Socket
Socket
Sign inDemoInstall

ajv

Package Overview
Dependencies
5
Maintainers
2
Versions
352
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 7.1.1 to 7.2.0

dist/compile/jtd/parse.d.ts

10

.tonic_example.js

@@ -1,5 +0,5 @@

var Ajv = require("ajv")
var ajv = new Ajv({allErrors: true})
const Ajv = require("ajv").default
const ajv = new Ajv({allErrors: true})
var schema = {
const schema = {
properties: {

@@ -11,3 +11,3 @@ foo: {type: "string"},

var validate = ajv.compile(schema)
const validate = ajv.compile(schema)

@@ -18,5 +18,5 @@ test({foo: "abc", bar: 2})

function test(data) {
var valid = validate(data)
const valid = validate(data)
if (valid) console.log("Valid!")
else console.log("Invalid: " + ajv.errorsText(validate.errors))
}

@@ -1,2 +0,2 @@

export { Format, FormatDefinition, AsyncFormatDefinition, KeywordDefinition, KeywordErrorDefinition, CodeKeywordDefinition, MacroKeywordDefinition, FuncKeywordDefinition, Vocabulary, Schema, SchemaObject, AnySchemaObject, AsyncSchema, AnySchema, ValidateFunction, AsyncValidateFunction, ErrorObject, ErrorNoParams, } from "./types";
export { Format, FormatDefinition, AsyncFormatDefinition, KeywordDefinition, KeywordErrorDefinition, CodeKeywordDefinition, MacroKeywordDefinition, FuncKeywordDefinition, Vocabulary, Schema, SchemaObject, AnySchemaObject, AsyncSchema, AnySchema, ValidateFunction, AsyncValidateFunction, SchemaValidateFunction, ErrorObject, ErrorNoParams, } from "./types";
export { Plugin, Options, CodeOptions, InstanceOptions, Logger, ErrorsTextOptions } from "./core";

@@ -3,0 +3,0 @@ export { SchemaCxt, SchemaObjCxt } from "./compile";

@@ -18,2 +18,3 @@ import type { ScopeValueSets, NameValue, ValueScope, ValueScopeName } from "./scope";

AND: _Code;
ADD: _Code;
};

@@ -46,2 +47,3 @@ export interface CodeGenOptions {

assign(lhs: Code, rhs: SafeExpr, sideEffects?: boolean): CodeGen;
add(lhs: Code, rhs: SafeExpr): CodeGen;
code(c: Block | SafeExpr): CodeGen;

@@ -48,0 +50,0 @@ object(...keyValues: [Name | string, SafeExpr | string][]): _Code;

@@ -29,2 +29,3 @@ "use strict";

AND: new code_1._Code("&&"),
ADD: new code_1._Code("+"),
};

@@ -83,2 +84,11 @@ class Node {

}
class AssignOp extends Assign {
constructor(lhs, op, rhs, sideEffects) {
super(lhs, rhs, sideEffects);
this.op = op;
}
render({ _n }) {
return `${this.lhs} ${this.op}= ${this.rhs};` + _n;
}
}
class Label extends Node {

@@ -423,2 +433,6 @@ constructor(label) {

}
// `+=` code
add(lhs, rhs) {
return this._leafNode(new AssignOp(lhs, exports.operators.ADD, rhs));
}
// appends passed SafeExpr to code or executes Block

@@ -425,0 +439,0 @@ code(c) {

@@ -20,2 +20,3 @@ import type { AnySchema, AnySchemaObject, AnyValidateFunction, EvaluatedProperties, EvaluatedItems } from "../types";

dataTypes: JSONType[];
definedProperties: Set<string>;
readonly topSchemaRef: Code;

@@ -65,2 +66,6 @@ readonly validateName: Name;

validateName?: ValueScopeName;
serialize?: (data: unknown) => string;
serializeName?: ValueScopeName;
parse?: (data: string) => unknown;
parseName?: ValueScopeName;
constructor(env: SchemaEnvArgs);

@@ -70,4 +75,5 @@ }

export declare function resolveRef(this: Ajv, root: SchemaEnv, baseId: string, ref: string): AnySchema | SchemaEnv | undefined;
export declare function getCompilingSchema(this: Ajv, schEnv: SchemaEnv): SchemaEnv | void;
export declare function resolveSchema(this: Ajv, root: SchemaEnv, // root object with properties schema, refs TODO below SchemaEnv is assigned to it
ref: string): SchemaEnv | undefined;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveSchema = exports.resolveRef = exports.compileSchema = exports.SchemaEnv = void 0;
exports.resolveSchema = exports.getCompilingSchema = exports.resolveRef = exports.compileSchema = exports.SchemaEnv = void 0;
const codegen_1 = require("./codegen");

@@ -60,2 +60,3 @@ const error_classes_1 = require("./error_classes");

dataTypes: [],
definedProperties: new Set(),
topSchemaRef: gen.scopeValue("schema", this.opts.code.source === true

@@ -155,2 +156,3 @@ ? { ref: sch.schema, code: codegen_1.stringify(sch.schema) }

}
exports.getCompilingSchema = getCompilingSchema;
function sameSchemaEnv(s1, s2) {

@@ -157,0 +159,0 @@ return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;

@@ -15,3 +15,7 @@ import { Name } from "./codegen";

scope: Name;
json: Name;
jsonPos: Name;
jsonLen: Name;
jsonPart: Name;
};
export default names;

@@ -21,4 +21,9 @@ "use strict";

scope: new codegen_1.Name("scope"),
// JTD serialize/parse name for JSON string and position
json: new codegen_1.Name("json"),
jsonPos: new codegen_1.Name("jsonPos"),
jsonLen: new codegen_1.Name("jsonLen"),
jsonPart: new codegen_1.Name("jsonPart"),
};
exports.default = names;
//# sourceMappingURL=names.js.map
import type { AnySchema, AnySchemaObject } from "../types";
import type Ajv from "../ajv";
import URI = require("uri-js");
import * as URI from "uri-js";
export declare type LocalRefs = {

@@ -5,0 +5,0 @@ [Ref in string]?: AnySchemaObject;

@@ -19,2 +19,3 @@ import type { AnySchema } from "../types";

dataTypes: JSONType[];
definedProperties: Set<string>;
propertyName: Name;

@@ -21,0 +22,0 @@ dataPropType: Type;

@@ -78,2 +78,3 @@ "use strict";

subschema.dataTypes = [];
it.definedProperties = new Set();
subschema.parentData = it.data;

@@ -80,0 +81,0 @@ subschema.dataNames = [...it.dataNames, _nextData];

@@ -1,1 +0,5 @@

export default function validTimestamp(str: string): boolean;
declare function validTimestamp(str: string): boolean;
declare namespace validTimestamp {
var code: import("./codegen/code")._Code;
}
export default validTimestamp;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const codegen_1 = require("./codegen");
const DATE_TIME = /^(\d\d\d\d)-(\d\d)-(\d\d)(?:t|\s)(\d\d):(\d\d):(\d\d)(?:\.\d+)?(?:z|([+-]\d\d)(?::?(\d\d))?)$/i;

@@ -29,2 +30,3 @@ const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

exports.default = validTimestamp;
validTimestamp.code = codegen_1._ `require("ajv/dist/compile/timestamp").default`;
//# sourceMappingURL=timestamp.js.map

@@ -31,2 +31,5 @@ import type { AnySchema, EvaluatedProperties, EvaluatedItems } from "../types";

}): void;
export declare function func(gen: CodeGen, f: {
code: Code;
}): Name;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setEvaluated = exports.evaluatedPropsToName = exports.mergeEvaluated = exports.eachItem = exports.unescapeJsonPointer = exports.escapeJsonPointer = exports.escapeFragment = exports.unescapeFragment = exports.schemaRefOrVal = exports.schemaHasRulesButRef = exports.schemaHasRules = exports.checkUnknownRules = exports.alwaysValidSchema = exports.toHash = void 0;
exports.func = exports.setEvaluated = exports.evaluatedPropsToName = exports.mergeEvaluated = exports.eachItem = exports.unescapeJsonPointer = exports.escapeJsonPointer = exports.escapeFragment = exports.unescapeFragment = exports.schemaRefOrVal = exports.schemaHasRulesButRef = exports.schemaHasRules = exports.checkUnknownRules = exports.alwaysValidSchema = exports.toHash = void 0;
const codegen_1 = require("./codegen");

@@ -141,2 +141,9 @@ const validate_1 = require("./validate");

exports.setEvaluated = setEvaluated;
function func(gen, f) {
return gen.scopeValue("func", {
ref: f,
code: f.code,
});
}
exports.func = func;
//# sourceMappingURL=util.js.map

@@ -15,5 +15,6 @@ "use strict";

var _a;
return (schema[rule.keyword] !== undefined || ((_a = rule.definition.implements) === null || _a === void 0 ? void 0 : _a.some((kwd) => schema[kwd] !== undefined)));
return (schema[rule.keyword] !== undefined ||
((_a = rule.definition.implements) === null || _a === void 0 ? void 0 : _a.some((kwd) => schema[kwd] !== undefined)));
}
exports.shouldUseRule = shouldUseRule;
//# sourceMappingURL=applicability.js.map

@@ -12,5 +12,7 @@ export { Format, FormatDefinition, AsyncFormatDefinition, KeywordDefinition, KeywordErrorDefinition, CodeKeywordDefinition, MacroKeywordDefinition, FuncKeywordDefinition, Vocabulary, Schema, SchemaObject, AnySchemaObject, AsyncSchema, AnySchema, ValidateFunction, AsyncValidateFunction, AnyValidateFunction, ErrorObject, ErrorNoParams, } from "./types";

export { JSONSchemaType } from "./types/json-schema";
export { JTDSchemaType } from "./types/jtd-schema";
export { _, str, stringify, nil, Name, Code, CodeGen, CodeGenOptions } from "./compile/codegen";
import type { Schema, AnySchema, AnySchemaObject, SchemaObject, AsyncSchema, Vocabulary, KeywordDefinition, AddedKeywordDefinition, AnyValidateFunction, ValidateFunction, AsyncValidateFunction, ErrorObject, Format, AddedFormat } from "./types";
import type { JSONSchemaType } from "./types/json-schema";
import type { JTDSchemaType } from "./types/jtd-schema";
import { ValidationError, MissingRefError } from "./compile/error_classes";

@@ -25,2 +27,3 @@ import { ValidationRules } from "./compile/rules";

strictTuples?: boolean | "log";
strictRequired?: boolean | "log";
allowMatchingProperties?: boolean;

@@ -121,8 +124,11 @@ allowUnionTypes?: boolean;

validate<T>(schema: Schema | JSONSchemaType<T> | string, data: unknown): data is T;
validate<T>(schema: JTDSchemaType<T>, data: unknown): data is T;
validate<T>(schema: AsyncSchema, data: unknown | T): Promise<T>;
validate<T>(schemaKeyRef: AnySchema | string, data: unknown): data is T | Promise<T>;
compile<T = unknown>(schema: Schema | JSONSchemaType<T>, _meta?: boolean): ValidateFunction<T>;
compile<T = unknown>(schema: JTDSchemaType<T>, _meta?: boolean): ValidateFunction<T>;
compile<T = unknown>(schema: AsyncSchema, _meta?: boolean): AsyncValidateFunction<T>;
compile<T = unknown>(schema: AnySchema, _meta?: boolean): AnyValidateFunction<T>;
compileAsync<T = unknown>(schema: SchemaObject | JSONSchemaType<T>, _meta?: boolean): Promise<ValidateFunction<T>>;
compileAsync<T = unknown>(schema: JTDSchemaType<T>, _meta?: boolean): Promise<ValidateFunction<T>>;
compileAsync<T = unknown>(schema: AsyncSchema, meta?: boolean): Promise<AsyncValidateFunction<T>>;

@@ -148,3 +154,3 @@ compileAsync<T = unknown>(schema: AnySchemaObject, meta?: boolean): Promise<AnyValidateFunction<T>>;

private _removeAllSchemas;
private _addSchema;
_addSchema(schema: AnySchema, meta?: boolean, validateSchema?: boolean | "log", addSchema?: boolean): SchemaEnv;
private _checkUnique;

@@ -151,0 +157,0 @@ private _compileSchemaEnv;

@@ -24,2 +24,4 @@ "use strict";

"validate",
"serialize",
"parse",
"wrapper",

@@ -26,0 +28,0 @@ "root",

@@ -1,2 +0,2 @@

export { Format, FormatDefinition, AsyncFormatDefinition, KeywordDefinition, KeywordErrorDefinition, CodeKeywordDefinition, MacroKeywordDefinition, FuncKeywordDefinition, Vocabulary, Schema, SchemaObject, AnySchemaObject, AsyncSchema, AnySchema, ValidateFunction, AsyncValidateFunction, ErrorObject, ErrorNoParams, } from "./types";
export { Format, FormatDefinition, AsyncFormatDefinition, KeywordDefinition, KeywordErrorDefinition, CodeKeywordDefinition, MacroKeywordDefinition, FuncKeywordDefinition, Vocabulary, Schema, SchemaObject, AnySchemaObject, AsyncSchema, AnySchema, ValidateFunction, AsyncValidateFunction, ErrorObject, ErrorNoParams, JTDParser, } from "./types";
export { Plugin, Options, CodeOptions, InstanceOptions, Logger, ErrorsTextOptions } from "./core";

@@ -7,3 +7,5 @@ export { SchemaCxt, SchemaObjCxt } from "./compile";

export { _, str, stringify, nil, Name, Code, CodeGen, CodeGenOptions } from "./compile/codegen";
import type { AnySchemaObject } from "./types";
import type { AnySchemaObject, SchemaObject, JTDParser } from "./types";
import type { JTDSchemaType, JTDDataType } from "./types/jtd-schema";
export { JTDSchemaType, JTDDataType };
import AjvCore, { CurrentOptions } from "./core";

@@ -38,2 +40,8 @@ export declare type JTDOptions = CurrentOptions & {

defaultMeta(): string | AnySchemaObject | undefined;
compileSerializer<T = unknown>(schema: SchemaObject): (data: T) => string;
compileSerializer<T = unknown>(schema: JTDSchemaType<T>): (data: T) => string;
compileParser<T = unknown>(schema: SchemaObject): JTDParser<T>;
compileParser<T = unknown>(schema: JTDSchemaType<T>): JTDParser<T>;
private _compileSerializer;
private _compileParser;
}

@@ -17,2 +17,4 @@ "use strict";

const jtd_schema_1 = require("./refs/jtd-schema");
const serialize_1 = require("./compile/jtd/serialize");
const parse_1 = require("./compile/jtd/parse");
// const META_SUPPORT_DATA = ["/properties"]

@@ -43,4 +45,26 @@ const META_SCHEMA_ID = "JTD-meta-schema";

}
compileSerializer(schema) {
const sch = this._addSchema(schema);
return sch.serialize || this._compileSerializer(sch);
}
compileParser(schema) {
const sch = this._addSchema(schema);
return (sch.parse || this._compileParser(sch));
}
_compileSerializer(sch) {
serialize_1.default.call(this, sch, sch.schema.definitions || {});
/* istanbul ignore if */
if (!sch.serialize)
throw new Error("ajv implementation error");
return sch.serialize;
}
_compileParser(sch) {
parse_1.default.call(this, sch, sch.schema.definitions || {});
/* istanbul ignore if */
if (!sch.parse)
throw new Error("ajv implementation error");
return sch.parse;
}
}
exports.default = Ajv;
//# sourceMappingURL=jtd.js.map

@@ -51,2 +51,7 @@ import type { CodeGen, Code, Name, ScopeValueSets, ValueScopeName } from "../compile/codegen";

}
export interface JTDParser<T = unknown> {
(json: string): T | undefined;
message?: string;
position?: number;
}
export declare type EvaluatedProperties = {

@@ -53,0 +58,0 @@ [K in string]?: true;

@@ -23,3 +23,3 @@ export declare type SomeJSONSchema = JSONSchemaType<Known, true>;

items: {
[K in keyof T]-?: JSONSchemaType<T[K]> & Nullable<T[K]>;
readonly [K in keyof T]-?: JSONSchemaType<T[K]> & Nullable<T[K]>;
} & {

@@ -45,3 +45,3 @@ length: T["length"];

type: JSONType<"object", _partial>;
required: _partial extends true ? (keyof T)[] : RequiredMembers<T>[];
required: _partial extends true ? Readonly<(keyof T)[]> : Readonly<RequiredMembers<T>[]>;
additionalProperties?: boolean | JSONSchemaType<T[string]>;

@@ -55,6 +55,6 @@ unevaluatedProperties?: boolean | JSONSchemaType<T[string]>;

dependencies?: {
[K in keyof T]?: (keyof T)[] | PartialSchema<T>;
[K in keyof T]?: Readonly<(keyof T)[]> | PartialSchema<T>;
};
dependentRequired?: {
[K in keyof T]?: (keyof T)[];
[K in keyof T]?: Readonly<(keyof T)[]>;
};

@@ -78,5 +78,5 @@ dependentSchemas?: {

};
allOf?: PartialSchema<T>[];
anyOf?: PartialSchema<T>[];
oneOf?: PartialSchema<T>[];
allOf?: Readonly<PartialSchema<T>[]>;
anyOf?: Readonly<PartialSchema<T>[]>;
oneOf?: Readonly<PartialSchema<T>[]>;
if?: PartialSchema<T>;

@@ -90,3 +90,3 @@ then?: PartialSchema<T>;

}
declare type PropertiesSchema<T> = {
export declare type PropertiesSchema<T> = {
[K in keyof T]-?: (JSONSchemaType<T[K]> & Nullable<T[K]>) | {

@@ -96,3 +96,3 @@ $ref: string;

};
declare type RequiredMembers<T> = {
export declare type RequiredMembers<T> = {
[K in keyof T]-?: undefined extends T[K] ? never : K;

@@ -103,9 +103,9 @@ }[keyof T];

const?: never;
enum?: (T | null)[];
enum?: Readonly<(T | null)[]>;
default?: T | null;
} : {
const?: T;
enum?: T[];
enum?: Readonly<T[]>;
default?: T;
};
export {};

@@ -44,9 +44,4 @@ "use strict";

// TODO maybe an option instead of hard-coded 8?
const hasProp = gen.scopeValue("func", {
// eslint-disable-next-line @typescript-eslint/unbound-method
ref: Object.prototype.hasOwnProperty,
code: codegen_1._ `Object.prototype.hasOwnProperty`,
});
const propsSchema = util_1.schemaRefOrVal(it, parentSchema.properties, "properties");
definedProp = codegen_1._ `${hasProp}.call(${propsSchema}, ${key})`;
definedProp = code_1.isOwnProperty(gen, propsSchema, key);
}

@@ -53,0 +48,0 @@ else if (props.length) {

@@ -15,3 +15,3 @@ "use strict";

depsCount: ${depsCount},
deps: ${deps}}`,
deps: ${deps}}`, // TODO change to reference
};

@@ -49,3 +49,3 @@ const def = {

continue;
const hasProperty = code_1.propertyInData(data, prop, it.opts.ownProperties);
const hasProperty = code_1.propertyInData(gen, data, prop, it.opts.ownProperties);
cxt.setParams({

@@ -77,3 +77,3 @@ property: prop,

continue;
gen.if(code_1.propertyInData(data, prop, it.opts.ownProperties), () => {
gen.if(code_1.propertyInData(gen, data, prop, it.opts.ownProperties), () => {
const schCxt = cxt.subschema({ keyword, schemaProp: prop }, valid);

@@ -80,0 +80,0 @@ cxt.mergeValidEvaluated(schCxt, valid);

@@ -17,2 +17,5 @@ "use strict";

const allProps = code_1.allSchemaProperties(schema);
for (const prop of allProps) {
it.definedProperties.add(prop);
}
if (it.opts.unevaluated && allProps.length && it.props !== true) {

@@ -30,3 +33,3 @@ it.props = util_1.mergeEvaluated.props(gen, util_1.toHash(allProps), it.props);

else {
gen.if(code_1.propertyInData(data, prop, it.opts.ownProperties));
gen.if(code_1.propertyInData(gen, data, prop, it.opts.ownProperties));
applyPropertySchema(prop);

@@ -37,2 +40,3 @@ if (!it.allErrors)

}
cxt.it.definedProperties.add(prop);
cxt.ok(valid);

@@ -39,0 +43,0 @@ }

@@ -6,6 +6,8 @@ import type { SchemaMap } from "../types";

export declare function checkReportMissingProp(cxt: KeywordCxt, prop: string): void;
export declare function checkMissingProp({ data, it: { opts } }: KeywordCxt, properties: string[], missing: Name): Code;
export declare function checkMissingProp({ gen, data, it: { opts } }: KeywordCxt, properties: string[], missing: Name): Code;
export declare function reportMissingProp(cxt: KeywordCxt, missing: Name): void;
export declare function propertyInData(data: Name, property: Name | string, ownProperties?: boolean): Code;
export declare function noPropertyInData(data: Name, property: Name | string, ownProperties?: boolean): Code;
export declare function hasPropFunc(gen: CodeGen): Name;
export declare function isOwnProperty(gen: CodeGen, data: Name, property: Name | string): Code;
export declare function propertyInData(gen: CodeGen, data: Name, property: Name | string, ownProperties?: boolean): Code;
export declare function noPropertyInData(gen: CodeGen, data: Name, property: Name | string, ownProperties?: boolean): Code;
export declare function allSchemaProperties(schemaMap?: SchemaMap): string[];

@@ -12,0 +14,0 @@ export declare function schemaProperties(it: SchemaCxt, schemaMap: SchemaMap): string[];

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateUnion = exports.validateArray = exports.usePattern = exports.callValidateCode = exports.schemaProperties = exports.allSchemaProperties = exports.noPropertyInData = exports.propertyInData = exports.reportMissingProp = exports.checkMissingProp = exports.checkReportMissingProp = void 0;
exports.validateUnion = exports.validateArray = exports.usePattern = exports.callValidateCode = exports.schemaProperties = exports.allSchemaProperties = exports.noPropertyInData = exports.propertyInData = exports.isOwnProperty = exports.hasPropFunc = exports.reportMissingProp = exports.checkMissingProp = exports.checkReportMissingProp = void 0;
const codegen_1 = require("../compile/codegen");

@@ -10,3 +10,3 @@ const util_1 = require("../compile/util");

const { gen, data, it } = cxt;
gen.if(noPropertyInData(data, prop, it.opts.ownProperties), () => {
gen.if(noPropertyInData(gen, data, prop, it.opts.ownProperties), () => {
cxt.setParams({ missingProperty: codegen_1._ `${prop}` }, true);

@@ -17,4 +17,4 @@ cxt.error();

exports.checkReportMissingProp = checkReportMissingProp;
function checkMissingProp({ data, it: { opts } }, properties, missing) {
return codegen_1.or(...properties.map((prop) => codegen_1._ `${noPropertyInData(data, prop, opts.ownProperties)} && (${missing} = ${prop})`));
function checkMissingProp({ gen, data, it: { opts } }, properties, missing) {
return codegen_1.or(...properties.map((prop) => codegen_1._ `${noPropertyInData(gen, data, prop, opts.ownProperties)} && (${missing} = ${prop})`));
}

@@ -27,13 +27,22 @@ exports.checkMissingProp = checkMissingProp;

exports.reportMissingProp = reportMissingProp;
function isOwnProperty(data, property) {
return codegen_1._ `Object.prototype.hasOwnProperty.call(${data}, ${property})`;
function hasPropFunc(gen) {
return gen.scopeValue("func", {
// eslint-disable-next-line @typescript-eslint/unbound-method
ref: Object.prototype.hasOwnProperty,
code: codegen_1._ `Object.prototype.hasOwnProperty`,
});
}
function propertyInData(data, property, ownProperties) {
exports.hasPropFunc = hasPropFunc;
function isOwnProperty(gen, data, property) {
return codegen_1._ `${hasPropFunc(gen)}.call(${data}, ${property})`;
}
exports.isOwnProperty = isOwnProperty;
function propertyInData(gen, data, property, ownProperties) {
const cond = codegen_1._ `${data}${codegen_1.getProperty(property)} !== undefined`;
return ownProperties ? codegen_1._ `${cond} && ${isOwnProperty(data, property)}` : cond;
return ownProperties ? codegen_1._ `${cond} && ${isOwnProperty(gen, data, property)}` : cond;
}
exports.propertyInData = propertyInData;
function noPropertyInData(data, property, ownProperties) {
function noPropertyInData(gen, data, property, ownProperties) {
const cond = codegen_1._ `${data}${codegen_1.getProperty(property)} === undefined`;
return ownProperties ? codegen_1._ `${cond} || !${isOwnProperty(data, property)}` : cond;
return ownProperties ? codegen_1._ `${cond} || !${isOwnProperty(gen, data, property)}` : cond;
}

@@ -40,0 +49,0 @@ exports.noPropertyInData = noPropertyInData;

@@ -61,3 +61,3 @@ "use strict";

for (const prop of props) {
gen.if(code_1.propertyInData(data, prop, it.opts.ownProperties), () => applyPropertySchema(prop, keyword, _valid), missingProperty);
gen.if(code_1.propertyInData(gen, data, prop, it.opts.ownProperties), () => applyPropertySchema(prop, keyword, _valid), missingProperty);
cxt.ok(_valid);

@@ -106,8 +106,3 @@ }

const propsSchema = util_1.schemaRefOrVal(it, parentSchema[keyword], keyword);
const hasProp = gen.scopeValue("func", {
// eslint-disable-next-line @typescript-eslint/unbound-method
ref: Object.prototype.hasOwnProperty,
code: codegen_1._ `Object.prototype.hasOwnProperty`,
});
additional = codegen_1._ `!${hasProp}.call(${propsSchema}, ${key})`;
additional = code_1.isOwnProperty(gen, propsSchema, key);
}

@@ -114,0 +109,0 @@ else if (props.length) {

@@ -1,3 +0,4 @@

import type { CodeKeywordDefinition } from "../../types";
import type { CodeKeywordDefinition, AnySchemaObject } from "../../types";
declare const def: CodeKeywordDefinition;
export declare function hasRef(schema: AnySchemaObject): boolean;
export default def;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasRef = void 0;
const compile_1 = require("../../compile");

@@ -53,13 +54,14 @@ const codegen_1 = require("../../compile/codegen");

}
function hasRef(schema) {
for (const key in schema) {
let sch;
if (key === "ref" || (typeof (sch = schema[key]) == "object" && hasRef(sch)))
return true;
}
return false;
}
},
};
function hasRef(schema) {
for (const key in schema) {
let sch;
if (key === "ref" || (typeof (sch = schema[key]) == "object" && hasRef(sch)))
return true;
}
return false;
}
exports.hasRef = hasRef;
exports.default = def;
//# sourceMappingURL=ref.js.map
import type { CodeKeywordDefinition } from "../../types";
export declare type IntType = "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32";
export declare const intRange: {
[T in IntType]: [number, number, number];
};
declare const def: CodeKeywordDefinition;
export default def;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.intRange = void 0;
const codegen_1 = require("../../compile/codegen");
const timestamp_1 = require("../../compile/timestamp");
const util_1 = require("../../compile/util");
const metadata_1 = require("./metadata");
const intRange = {
int8: [-128, 127],
uint8: [0, 255],
int16: [-32768, 32767],
uint16: [0, 65535],
int32: [-2147483648, 2147483647],
uint32: [0, 4294967295],
exports.intRange = {
int8: [-128, 127, 3],
uint8: [0, 255, 3],
int16: [-32768, 32767, 5],
uint16: [0, 65535, 5],
int32: [-2147483648, 2147483647, 10],
uint32: [0, 4294967295, 10],
};

@@ -27,6 +29,3 @@ const def = {

case "timestamp": {
const vts = gen.scopeValue("func", {
ref: timestamp_1.default,
code: codegen_1._ `require("ajv/dist/compile/timestamp").default`,
});
const vts = util_1.func(gen, timestamp_1.default);
cond = codegen_1._ `${data} instanceof Date || (typeof ${data} == "string" && ${vts}(${data}))`;

@@ -40,3 +39,3 @@ break;

default: {
const [min, max] = intRange[schema];
const [min, max] = exports.intRange[schema];
cond = codegen_1._ `typeof ${data} == "number" && isFinite(${data}) && ${data} >= ${min} && ${data} <= ${max} && !(${data} % 1)`;

@@ -43,0 +42,0 @@ }

@@ -5,2 +5,3 @@ "use strict";

const codegen_1 = require("../../compile/codegen");
const validate_1 = require("../../compile/validate");
const error = {

@@ -26,2 +27,13 @@ message: ({ params: { missingProperty } }) => codegen_1.str `should have required property '${missingProperty}'`,

exitOnErrorMode();
if (opts.strictRequired) {
const props = cxt.parentSchema.properties;
const { definedProperties } = cxt.it;
for (const requiredKey of schema) {
if ((props === null || props === void 0 ? void 0 : props[requiredKey]) === undefined && !definedProperties.has(requiredKey)) {
const schemaPath = it.schemaEnv.baseId + it.errSchemaPath;
const msg = `required property "${requiredKey}" is not defined at "${schemaPath}" (strictRequired)`;
validate_1.checkStrictMode(it, msg, it.opts.strictRequired);
}
}
}
function allErrorsMode() {

@@ -53,3 +65,3 @@ if (useLoop || $data) {

cxt.setParams({ missingProperty: prop });
gen.if(code_1.noPropertyInData(data, prop, opts.ownProperties), () => cxt.error());
gen.if(code_1.noPropertyInData(gen, data, prop, opts.ownProperties), () => cxt.error());
});

@@ -60,3 +72,3 @@ }

gen.forOf(missing, schemaCode, () => {
gen.assign(valid, code_1.propertyInData(data, missing, opts.ownProperties));
gen.assign(valid, code_1.propertyInData(gen, data, missing, opts.ownProperties));
gen.if(codegen_1.not(valid), () => {

@@ -63,0 +75,0 @@ cxt.error();

# API Reference
- [Ajv constructor and methods](#ajv-constructor-and-methods)
- [Options](#options)
- [Validation errors](#validation-errors)
[[toc]]
## Ajv constructor and methods
#### new Ajv(options: object)
### new Ajv(options: object)

@@ -17,9 +15,9 @@ Create Ajv instance:

See [Options](#options)
See [Options](./options)
#### ajv.compile(schema: object): (data: any) =\> boolean | Promise\<any\>
### ajv.compile(schema: object): (data: any) => boolean | Promise < any >
Generate validating function and cache the compiled schema for future use.
Validating function returns a boolean value (or promise for async schemas that must have `$async: true` property - see [Asynchronous validation](./validation.md#asynchronous-validation)). This function has properties `errors` and `schema`. Errors encountered during the last validation are assigned to `errors` property (it is assigned `null` if there was no errors). `schema` property contains the reference to the original schema.
Validating function returns a boolean value (or promise for async schemas that must have `$async: true` property - see [Asynchronous validation](./guide/async-validation.md)). This function has properties `errors` and `schema`. Errors encountered during the last validation are assigned to `errors` property (it is assigned `null` if there was no errors). `schema` property contains the reference to the original schema.

@@ -54,4 +52,77 @@ The schema passed to this method will be validated against meta-schema unless `validateSchema` option is false. If schema is invalid, an error will be thrown. See [options](#options).

#### <a name="api-compileAsync"></a>ajv.compileAsync(schema: object, meta?: boolean): Promise\<Function\>
<a name="jtd-serialize"></a>
### ajv.compileSerializer(schema: object): (data: any) => string <Badge text="NEW" />
Generate serializing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below).
Serializers compiled from JTD schemas can be more than 10 times faster than using `JSON.stringify`, because they do not traverse all the data, only the properties that are defined in the schema.
Properties not defined in the schema will not be included in serialized JSON, unless the schema has `additionalProperties: true` flag. It can also be beneficial from the application security point of view, as it prevents leaking accidentally/temporarily added additional properties to the API responses.
If you use JTD with typescript, the type for the schema can be derived from the data type, and generated serializer would only accept correct data type in this case:
```typescript
import Ajv, {JTDSchemaType} from "ajv/dist/jtd"
const ajv = new Ajv()
interface MyData = {
foo: number
bar?: string
}
const mySchema: JTDSchemaType<MyData> = {
properties: {
foo: {type: "int32"} // any JTD number type would be accepted here
},
optionalProperties: {
bar: {type: "string"}
}
}
const serializeMyData = ajv.compileSerializer(mySchema)
// serializeMyData has type (x: MyData) => string
// it prevents you from accidentally passing the wrong type
```
::: warning Please note
Compiled serializers do NOT validate passed data, it is assumed that the data is valid according to the schema. In the future there may be an option added that would make serializers also validate the data.
:::
<a name="jtd-parse"></a>
### ajv.compileParser(schema: object): (json: string) => any <Badge text="NEW" />
Generate parsing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below).
Parsers compiled from JTD schemas have comparable performance to `JSON.parse`<sup>\*</sup> in case JSON string is valid according to the schema (and they do not just parse JSON - they ensure that parsed JSON is valid according to the schema as they parse), but they can be many times faster in case the string is invalid - for example, if schema expects an object, and JSON string is array the parser would fail on the first character.
Parsing will fail if there are properties not defined in the schema, unless the schema has `additionalProperties: true` flag.
If you use JTD with typescript, the type for the schema can be derived from the data type, and generated parser will return correct data type (see definitions example in the [serialize](#jtd-serialize) section):
```typescript
const parseMyData = ajv.compileParser(mySchema)
// parseMyData has type (s: string) => MyData | undefined
// it returns correct data type in case parsing is successful and undefined if not
const validData = parseMyData('{"foo":1}') // {foo: 1} - success
const invalidData = parseMyData('{"x":1}') // undefined - failure
console.log(parseMyData.position) // 4
console.log(parseMyData.message) // property x not allowed
```
::: warning Please note
Generated parsers is a NEW Ajv functionality (as of March 2021), there can be some edge cases that are not handled correctly - please report any issues/submit fixes.
:::
<sup>\*</sup> As long as empty schema `{}` is not used - there is a possibility to improve performance in this case. Also, the performance of parsing `discriminator` schemas depends on the position of discriminator tag in the schema - the best parsing performance will be achieved if the tag is the first property - this is how compiled JTD serializers generate JSON in case of discriminator schemas.
<a name="api-compileAsync"></a>
### ajv.compileAsync(schema: object, meta?: boolean): Promise < Function >
Asynchronous version of `compile` method that loads missing remote schemas using asynchronous function in `options.loadSchema`. This function returns a Promise that resolves to a validation function. An optional callback passed to `compileAsync` will be called with 2 parameters: error (or null) and validating function. The returned promise will reject (and the callback will be called with an error) when:

@@ -69,5 +140,5 @@

See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation).
See example in [Asynchronous compilation](./guide/managing-schemas.md#asynchronous-schema-compilation).
#### ajv.validate(schemaOrRef: object | string, data: any): boolean
### ajv.validate(schemaOrRef: object | string, data: any): boolean

@@ -82,8 +153,12 @@ Validate data using passed schema (it will be compiled and cached).

**Please note**: every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later.
::: warning Please note
Every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later.
:::
If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](./validation.md#asynchronous-validation).
If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](./guide/async-validation.md).
#### <a name="add-schema"></a>ajv.addSchema(schema: object | object[], key?: string): Ajv
<a name="add-schema"></a>
### ajv.addSchema(schema: object | object[], key?: string): Ajv
Add schema(s) to validator instance. This method does not compile schemas (but it still validates them). Because of that dependencies can be added in any order and circular dependencies are supported. It also prevents unnecessary compilation of schemas that are containers for other schemas but not used as a whole.

@@ -101,3 +176,4 @@

**Please note**: Ajv return it instance for method chaining from all methods with the prefix `add*` and `remove*`:
::: tip Please note
Ajv return it instance for method chaining from all methods with the prefix `add*` and `remove*`:

@@ -108,4 +184,6 @@ ```javascript

#### ajv.addMetaSchema(schema: object | object[], key?: string): Ajv
:::
### ajv.addMetaSchema(schema: object | object[], key?: string): Ajv
Adds meta schema(s) that can be used to validate other schemas. That function should be used instead of `addSchema` because there may be instance options that would compile a meta schema incorrectly (at the moment it is `removeAdditional` option).

@@ -115,4 +193,6 @@

#### <a name="api-validateschema"></a>ajv.validateSchema(schema: object): boolean
<a name="api-validateschema"></a>
### ajv.validateSchema(schema: object): boolean
Validates schema. This method should be used to validate schemas rather than `validate` due to the inconsistency of `uri` format in JSON Schema standard.

@@ -128,7 +208,7 @@

#### ajv.getSchema(key: string): undefined | ((data: any) =\> boolean | Promise\<any\>)
### ajv.getSchema(key: string): undefined | ((data: any) => boolean | Promise < any >)
Retrieve compiled schema previously added with `addSchema` by the key passed to `addSchema` or by its full reference (id). The returned validating function has `schema` property with the reference to the original schema.
#### ajv.removeSchema(schemaOrRef: object | string | RegExp): Ajv
### ajv.removeSchema(schemaOrRef: object | string | RegExp): Ajv

@@ -146,4 +226,6 @@ Remove added/cached schema. Even if schema is referenced by other schemas it can be safely removed as dependent schemas have local references.

#### <a name="api-addformat"></a>ajv.addFormat(name: string, format: Format): Ajv
<a name="api-addformat"></a>
### ajv.addFormat(name: string, format: Format): Ajv
```typescript

@@ -178,4 +260,6 @@ type Format =

#### <a name="api-addkeyword"></a>ajv.addKeyword(definition: object):s Ajv
<a name="api-addkeyword"></a>
### ajv.addKeyword(definition: object): Ajv
Add validation keyword to Ajv instance.

@@ -215,3 +299,3 @@

// this option MUST NOT be used with `macro` keywords.
$data?: true // to support [\$data reference](./validation.md#data-reference) as the value of keyword.
$data?: true // to support [\$data reference](./guide/combining-schemas.md#data-reference) as the value of keyword.
// The reference will be resolved at validation time. If the keyword has meta-schema,

@@ -232,13 +316,15 @@ // it would be extended to allow $data and it will be used to validate the resolved value.

`compile`, `macro` and `code` are mutually exclusive, only one should be used at a time. `validate` can be used separately or in addition to `compile` or `macro` to support [\$data reference](./validation.md#data-reference).
`compile`, `macro` and `code` are mutually exclusive, only one should be used at a time. `validate` can be used separately or in addition to `compile` or `macro` to support [\$data reference](./guide/combining-schemas.md#data-reference).
**Please note**: If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed.
::: tip Please note
If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed.
:::
See [User defined keywords](./keywords.md) for more details.
#### ajv.getKeyword(keyword: string): object | boolean
### ajv.getKeyword(keyword: string): object | boolean
Returns keyword definition, `false` if the keyword is unknown.
#### ajv.removeKeyword(keyword: string): Ajv
### ajv.removeKeyword(keyword: string): Ajv

@@ -249,5 +335,7 @@ Removes added or pre-defined keyword so you can redefine them.

**Please note**: schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again.
::: warning Please note
The schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again.
:::
#### ajv.errorsText(errors?: object[], options?: object): string
### ajv.errorsText(errors?: object[], options?: object): string

@@ -258,154 +346,5 @@ Returns the text with all errors in a String.

## Options
Option defaults:
```javascript
// see types/index.ts for actual types
const defaultOptions = {
// strict mode options (NEW)
strict: true,
strictTypes: "log", // *
strictTuples: "log", // *
allowUnionTypes: false, // *
allowMatchingProperties: false, // *
validateFormats: true, // *
// validation and reporting options:
$data: false, // *
allErrors: false,
verbose: false, // *
$comment: false, // *
formats: {},
keywords: {},
schemas: {},
logger: undefined,
loadSchema: undefined, // *, function(uri: string): Promise {}
// options to modify validated data:
removeAdditional: false,
useDefaults: false, // *
coerceTypes: false, // *
// advanced options:
meta: true,
validateSchema: true,
addUsedSchema: true,
inlineRefs: true,
passContext: false,
loopRequired: Infinity, // *
loopEnum: Infinity, // NEW
ownProperties: false,
multipleOfPrecision: undefined, // *
messages: true, // false with JTD
ajvErrors: false // only with JTD
code: {
// NEW
es5: false,
lines: false,
source: false,
process: undefined, // (code: string) => string
optimize: true,
},
}
```
<sup>\*</sup> these options are not supported with JSON Type Definition schemas
#### Strict mode options (NEW in v7)
- _strict_: By default Ajv executes in strict mode, that is designed to prevent any unexpected behaviours or silently ignored mistakes in schemas (see [Strict Mode](./strict-mode.md) for more details). It does not change any validation results, but it makes some schemas invalid that would be otherwise valid according to JSON Schema specification. Option values:
- `true` (default) - use strict mode and throw an exception when any strict mode restriction is violated.
- `"log"` - log warning when any strict mode restriction is violated.
- `false` - ignore all strict mode restrictions. Also ignores `strictTypes` restrictions unless it is explicitly passed.
- _strictTypes_: By default Ajv logs warning when "type" keyword is used in a way that may be incorrect or confusing to other people - see [Strict types](./strict-mode.md#strict-types) for more details. This option does not change validation results. Option values:
- `true` - throw exception when any strictTypes restriction is violated.
- `"log"` (default, unless option strict is `false`) - log warning when any strictTypes restriction is violated.
- `false` - ignore all strictTypes restrictions violations.
- _strictTuples_: By default Ajv logs warning when "items" is array and "minItems" and "maxItems"/"additionalItems" not present or different from the number of items. See [Strict mode](./strict-mode.md) for more details. This option does not change validation results. Option values:
- `true` - throw exception.
- `"log"` (default, unless option strict is `false`) - log warning.
- `false` - ignore strictTuples restriction violations.
- _allowUnionTypes_: pass true to allow using multiple non-null types in "type" keyword (one of `strictTypes` restrictions). see [Strict types](./strict-mode.md#strict-types)
- _allowMatchingProperties_: pass true to allow overlap between "properties" and "patternProperties". Does not affect other strict mode restrictions. See [Strict Mode](./strict-mode.md).
- _validateFormats_: format validation. Option values:
- `true` (default) - validate formats (see [Formats](./validation.md#formats)). In [strict mode](./strict-mode.md) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./validation.md#data-reference)).
- `false` - do not validate any format keywords (TODO they will still collect annotations once supported).
#### Validation and reporting options
- _\$data_: support [\$data references](./validation.md#data-reference). Draft 6 meta-schema that is added by default will be extended to allow them. If you want to use another meta-schema you need to use $dataMetaSchema method to add support for $data reference. See [API](#ajv-constructor-and-methods).
- _allErrors_: check all rules collecting all errors. Default is to return after the first error.
- _verbose_: include the reference to the part of the schema (`schema` and `parentSchema`) and validated data in errors (false by default).
- _\$comment_: log or pass the value of `$comment` keyword to a function. Option values:
- `false` (default): ignore \$comment keyword.
- `true`: log the keyword value to console.
- function: pass the keyword value, its schema path and root schema to the specified function
- _formats_: an object with format definitions. Keys and values will be passed to `addFormat` method. Pass `true` as format definition to ignore some formats.
- _keywords_: an array of keyword definitions or strings. Values will be passed to `addKeyword` method.
- _schemas_: an array or object of schemas that will be added to the instance. In case you pass the array the schemas must have IDs in them. When the object is passed the method `addSchema(value, key)` will be called for each schema in this object.
- _logger_: sets the logging method. Default is the global `console` object that should have methods `log`, `warn` and `error`. See [Error logging](#error-logging). Option values:
- logger instance - it should have methods `log`, `warn` and `error`. If any of these methods is missing an exception will be thrown.
- `false` - logging is disabled.
- _loadSchema_: asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation).
#### Options to modify validated data
- _removeAdditional_: remove additional properties - see example in [Removing additional properties](./validation.md#removing-additional-properties). This option is not used if schema is added with `addMetaSchema` method. Option values:
- `false` (default) - not to remove additional properties
- `"all"` - all additional properties are removed, regardless of `additionalProperties` keyword in schema (and no validation is made for them).
- `true` - only additional properties with `additionalProperties` keyword equal to `false` are removed.
- `"failing"` - additional properties that fail schema validation will be removed (where `additionalProperties` keyword is `false` or schema).
- _useDefaults_: replace missing or undefined properties and items with the values from corresponding `default` keywords. Default behaviour is to ignore `default` keywords. This option is not used if schema is added with `addMetaSchema` method. See examples in [Assigning defaults](./validation.md#assigning-defaults). Option values:
- `false` (default) - do not use defaults
- `true` - insert defaults by value (object literal is used).
- `"empty"` - in addition to missing or undefined, use defaults for properties and items that are equal to `null` or `""` (an empty string).
- _coerceTypes_: change data type of data to match `type` keyword. See the example in [Coercing data types](./validation.md#coercing-data-types) and [coercion rules](./coercion.md). Option values:
- `false` (default) - no type coercion.
- `true` - coerce scalar data types.
- `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema).
#### Advanced options
- _meta_: add [meta-schema](http://json-schema.org/documentation.html) so it can be used by other schemas (true by default). If an object is passed, it will be used as the default meta-schema for schemas that have no `$schema` keyword. This default meta-schema MUST have `$schema` keyword.
- _validateSchema_: validate added/compiled schemas against meta-schema (true by default). `$schema` property in the schema can be http://json-schema.org/draft-07/schema or absent (draft-07 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. Option values:
- `true` (default) - if the validation fails, throw the exception.
- `"log"` - if the validation fails, log error.
- `false` - skip schema validation.
- _addUsedSchema_: by default methods `compile` and `validate` add schemas to the instance if they have `$id` (or `id`) property that doesn't start with "#". If `$id` is present and it is not unique the exception will be thrown. Set this option to `false` to skip adding schemas to the instance and the `$id` uniqueness check when these methods are used. This option does not affect `addSchema` method.
- _inlineRefs_: Affects compilation of referenced schemas. Option values:
- `true` (default) - the referenced schemas that don't have refs in them are inlined, regardless of their size - it improves performance.
- `false` - to not inline referenced schemas (they will always be compiled as separate functions).
- integer number - to limit the maximum number of keywords of the schema that will be inlined (to balance the total size of compiled functions and performance).
- _passContext_: pass validation context to _compile_ and _validate_ keyword functions. If this option is `true` and you pass some context to the compiled validation function with `validate.call(context, data)`, the `context` will be available as `this` in your keywords. By default `this` is Ajv instance.
- _loopRequired_: by default `required` keyword is compiled into a single expression (or a sequence of statements in `allErrors` mode). In case of a very large number of properties in this keyword it may result in a very big validation function. Pass integer to set the number of properties above which `required` keyword will be validated in a loop - smaller validation function size but also worse performance.
- _loopEnum_ (NEW in v7): by default `enum` keyword is compiled into a single expression. In case of a very large number of allowed values it may result in a large validation function. Pass integer to set the number of values above which `enum` keyword will be validated in a loop.
- _ownProperties_: by default Ajv iterates over all enumerable object properties; when this option is `true` only own enumerable object properties (i.e. found directly on the object rather than on its prototype) are iterated. Contributed by @mbroadst.
- _multipleOfPrecision_: by default `multipleOf` keyword is validated by comparing the result of division with parseInt() of that result. It works for dividers that are bigger than 1. For small dividers such as 0.01 the result of the division is usually not integer (even when it should be integer, see issue [#84](https://github.com/ajv-validator/ajv/issues/84)). If you need to use fractional dividers set this option to some positive integer N to have `multipleOf` validated using this formula: `Math.abs(Math.round(division) - division) < 1e-N` (it is slower but allows for float arithmetic deviations).
- _messages_: Include human-readable messages in errors. `true` by default. `false` can be passed when messages are generated outside of Ajv code (e.g. with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n)).
- _ajvErrors_: this option is only supported with JTD schemas to generate error objects with the properties described in the first part of [Validation errors](#validation-errors) section, otherwise JTD errors are generated when JTD schemas are used (see the second part of [the same section](#validation-errors)).
- _code_ (new in v7): code generation options:
```typescript
type CodeOptions = {
es5?: boolean // to generate es5 code - by default code is es6, with "for-of" loops, "let" and "const"
lines?: boolean // add line-breaks to code - to simplify debugging of generated functions
source?: boolean // add `source` property (see Source below) to validating function.
process?: (code: string, schema?: SchemaEnv) => string // an optional function to process generated code
// before it is passed to Function constructor.
// It can be used to either beautify or to transpile code.
optimize?: boolean | number // code optimization flag or number of passes, 1 pass by default,
// code optimizations reduce the size of the generated code (bytes, based on the tests) by over 10%,
// the number of code tree nodes by nearly 17%.
// You would almost never need more than one optimization pass, unless you have some really complex schemas -
// the second pass in the tests (it has quite complex schemas) only improves optimization by less than 0.1%.
// See [Code optimization](./codegen.md#code-optimization) for details.
}
type Source = {
code: string // unlike func.toString() it includes assignments external to function scope
scope: Scope // see Code generation (TODO)
}
```
## Validation errors
In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](./validation.md#asynchronous-validation), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property.
In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](./guide/async-validation.md), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property.

@@ -445,3 +384,5 @@ ### Error objects

**Please note**: Ajv is not fully consistent with JTD regarding the error objects in some scenarios - it will be consistent by the time Ajv version 8 is released. Therefore it is not recommended yet to use error objects for any advanced application logic.
::: warning Please note
Ajv is not fully consistent with JTD regarding the error objects in some scenarios - it will be consistent by the time Ajv version 8 is released. Therefore it is not recommended yet to use error objects for any advanced application logic.
:::

@@ -574,1 +515,5 @@ ### Error parameters

```
##### Options
This section is moved to [Initialization options](./options) page

@@ -1,5 +0,7 @@

# Code generation
# Code generation design
Starting from v7 Ajv uses [CodeGen module](../lib/compile/codegen/index.ts) that replaced [doT](https://github.com/olado/dot) templates used earlier.
[[toc]]
Starting from v7 Ajv uses [CodeGen module](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts) that replaced [doT](https://github.com/olado/dot) templates used earlier.
The motivations for this change:

@@ -40,3 +42,3 @@

// msg is _Code instance, so it will be inserted via another template without quotes
gen.code(_`console log(${msg})`)
gen.code(_`console.log(${msg})`)
}

@@ -56,3 +58,3 @@ ```

`.const`, `.if` and `.code` above are methods of CodeGen class that generate code inside class instance `gen` - see [source code](../lib/compile/codegen/index.ts) for all available methods and [tests](../spec/codegen.spec.ts) for other code generation examples.
`.const`, `.if` and `.code` above are methods of CodeGen class that generate code inside class instance `gen` - see [source code](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts) for all available methods and [tests](../spec/codegen.spec.ts) for other code generation examples.

@@ -71,3 +73,5 @@ These methods only accept instances of private class `_Code`, other values will be rejected by Typescript compiler - the risk to pass unsafe string is mitigated on type level.

**Please note**: These optimizations assume that the expressions in `if` conditions, `for` statement headers and assigned expressions are free of any side effects - this is the case for all pre-defined validation keywords.
::: warning Please note
These optimizations assume that the expressions in `if` conditions, `for` statement headers and assigned expressions are free of any side effects - this is the case for all pre-defined validation keywords.
:::

@@ -89,2 +93,4 @@ See [these tests](../spec/codegen.spec.ts) for examples.

**Please note**: If your user-defined keywords need to have side-effects that are removed by optimization (see above), you may need to disable it.
::: warning Please note
If your user-defined keywords need to have side-effects that are removed by optimization (see above), you may need to disable it.
:::

@@ -1,4 +0,4 @@

# Ajv type coercion rules
# Type coercion rules
To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](./validation.md#coercing-data-types).
To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](./guide/modifying-data.md#coercing-data-types).

@@ -5,0 +5,0 @@ The coercion rules are different from JavaScript:

# Code components
[[toc]]
## Ajv classes
[lib/core.ts](../lib/core.ts) - core Ajv class without any keywords. All Ajv methods for managing schemas and extensions are defined in this class.
[lib/core.ts](https://github.com/ajv-validator/ajv/blob/master/lib/core.ts) - core Ajv class without any keywords. All Ajv methods for managing schemas and extensions are defined in this class.
[lib/ajv.ts](../lib/ajv.ts) - subclass of Ajv core with JSON Schema draft-07 keywords.
[lib/ajv.ts](https://github.com/ajv-validator/ajv/blob/master/lib/ajv.ts) - subclass of Ajv core with JSON Schema draft-07 keywords.
[lib/2019.ts](../lib/2019.ts) - subclass of Ajv core with JSON Schema draft-2019-09 keywords.
[lib/2019.ts](https://github.com/ajv-validator/ajv/blob/master/lib/2019.ts) - subclass of Ajv core with JSON Schema draft-2019-09 keywords.
[lib/jtd.ts](https://github.com/ajv-validator/ajv/blob/master/lib/jtd.ts) - subclass of Ajv core with JSON Type Definition support.
## Schema compilation
[lib/compile](../lib/compile) - code for schema compilation
[lib/compile](https://github.com/ajv-validator/ajv/blob/master/lib/compile) - code for schema compilation
[lib/compile/index.ts](../lib/compile/index.ts) - the main recursive function code for schema compilation, functions for reference resolution, the interface for schema compilation context (`SchemaCxt`).
[lib/compile/index.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/index.ts) - the main recursive function code for schema compilation, functions for reference resolution, the interface for schema compilation context (`SchemaCxt`).
[lib/compile/context.ts](../lib/compile/context.ts) - the class for keyword code generation `KeywordCxt`. All pre-defined keywords and user-defined keywords that use `code` function are passed an instance of this class.
[lib/compile/context.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts) - the class for keyword code generation `KeywordCxt`. All pre-defined keywords and user-defined keywords that use `code` function are passed an instance of this class.
[lib/compile/rules.ts](../lib/compile/rules.ts) - data structure to store references to all all keyword definitions that were added to Ajv instance, organised by data type.
[lib/compile/rules.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/rules.ts) - data structure to store references to all all keyword definitions that were added to Ajv instance, organised by data type.
[lib/compile/subschema.ts](../lib/compile/subschema.ts) - creates schema context (`SchemaCxt`) to generate code for subschemas - used by all applicator keywords in [lib/vocabularies/applicator](../lib/vocabularies/applicator).
[lib/compile/subschema.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/subschema.ts) - creates schema context (`SchemaCxt`) to generate code for subschemas - used by all applicator keywords in [lib/vocabularies/applicator](https://github.com/ajv-validator/ajv/blob/master/lib/vocabularies/applicator).
[lib/compile/codegen](../lib/compile/codegen) - the api for [code generation](./codegen.md).
[lib/compile/codegen](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen) - the api for [code generation](./codegen.md).
[lib/compile/validate](../lib/compile/validate) - code to iterate the schema to generate code of validation function.
[lib/compile/validate](https://github.com/ajv-validator/ajv/blob/master/lib/compile/validate) - code to iterate the schema to generate code of validation function.
## Other components
[lib/standalone](../lib/standalone) - module to generate [standalone validation code](./standalone.md).
[lib/standalone](https://github.com/ajv-validator/ajv/blob/master/lib/standalone) - module to generate [standalone validation code](./standalone.md).
[lib/vocabularies](../lib/vocabularies) - pre-defined validation keywords.
[lib/vocabularies](https://github.com/ajv-validator/ajv/blob/master/lib/vocabularies) - pre-defined validation keywords.
[lib/refs](../lib/refs) - JSON Schema meta-schemas.
[lib/refs](https://github.com/ajv-validator/ajv/blob/master/lib/refs) - JSON Schema meta-schemas.

@@ -5,2 +5,4 @@ # Frequently Asked Questions

[[toc]]
## Using JSON schema

@@ -11,3 +13,3 @@

- [JSON Schema specification](https://tools.ietf.org/html/draft-handrews-json-schema-validation-00) (draft-07)
- [Validation keywords](./json-schema.md) in Ajv documentation
- [JSON Schema reference](./json-schema.md) in Ajv documentation
- [JSON Schema tutorial](https://spacetelescope.github.io/understanding-json-schema/) (for draft-04)

@@ -81,7 +83,7 @@

## Generating schemas with resolved references (\$ref)
## Generating schemas with resolved references ($ref)
See [#22](https://github.com/ajv-validator/ajv/issues/22), [#125](https://github.com/ajv-validator/ajv/issues/125), [#146](https://github.com/ajv-validator/ajv/issues/146), [#228](https://github.com/ajv-validator/ajv/issues/228), [#336](https://github.com/ajv-validator/ajv/issues/336), [#454](https://github.com/ajv-validator/ajv/issues/454).
#### Why Ajv does not replace references (\$ref) with the actual referenced schemas as some validators do?
#### Why Ajv does not replace references ($ref) with the actual referenced schemas as some validators do?

@@ -88,0 +90,0 @@ 1. The scope of Ajv is validating data against JSON Schemas; inlining referenced schemas is not necessary for validation. When Ajv generates code for validation it either inlines the code of referenced schema or uses function calls. Doing schema manipulation is more complex and out of scope.

@@ -1,2 +0,2 @@

# JSON Schema validation keywords
# JSON Schema

@@ -7,2 +7,4 @@ In a simple way, JSON Schema is an object with validation keywords.

[[toc]]
## JSON Schema draft-2019-09

@@ -17,45 +19,6 @@

- [maxContains/minContains](#maxcontains--mincontains)
- [$recursiveAnchor/$recursiveRef](./validation.md#extending-recursive-schemas)
- [$recursiveAnchor/$recursiveRef](./guide/combining-schemas.md#extending-recursive-schemas)
There is also support for [$dynamicAnchor/$dynamicRef](./validation.md#extending-recursive-schemas) from the next version of JSON Schema draft that will replace `$recursiveAnchor`/`$recursiveRef`.
There is also support for [$dynamicAnchor/$dynamicRef](./guide/combining-schemas.md#extending-recursive-schemas) from the next version of JSON Schema draft that will replace `$recursiveAnchor`/`$recursiveRef`.
## Included keywords
- [type](#type)
- [Keywords for numbers](#keywords-for-numbers)
- [maximum / minimum and exclusiveMaximum / exclusiveMinimum](#maximum--minimum-and-exclusivemaximum--exclusiveminimum)
- [multipleOf](#multipleof)
- [Keywords for strings](#keywords-for-strings)
- [maxLength/minLength](#maxlength--minlength)
- [pattern](#pattern)
- [format](#format)
- [Keywords for arrays](#keywords-for-arrays)
- [maxItems/minItems](#maxitems--minitems)
- [uniqueItems](#uniqueitems)
- [items](#items)
- [additionalItems](#additionalitems)
- [contains](#contains)
- [maxContains/minContains](#maxcontains--mincontains)
- [unevaluatedItems](#unevaluateditems) (NEW: added in draft 2019-09)
- [Keywords for objects](#keywords-for-objects)
- [maxProperties/minProperties](#maxproperties--minproperties)
- [required](#required)
- [properties](#properties)
- [patternProperties](#patternproperties)
- [additionalProperties](#additionalproperties)
- [dependencies](#dependencies) (deprecated from draft 2019-09)
- [dependentRequired](#dependentrequired) (NEW: added in draft 2019-09)
- [dependentSchemas](#dependentschemas) (NEW: added in draft 2019-09)
- [propertyNames](#propertynames)
- [unevaluatedProperties](#unevaluatedproperties) (NEW: added in draft 2019-09)
- [Keywords for all types](#keywords-for-all-types)
- [enum](#enum)
- [const](#const) (added in draft-06)
- [Compound keywords](#compound-keywords)
- [not](#not)
- [oneOf](#oneof)
- [anyOf](#anyof)
- [allOf](#allof)
- [if/then/else](#ifthenelse)
## `type`

@@ -101,3 +64,5 @@

**Please note**: Boolean value for keywords `exclusiveMaximum` (`exclusiveMinimum`) is no longer supported.
::: warning Please note
Boolean value for keywords `exclusiveMaximum` (`exclusiveMinimum`) is no longer supported.
:::

@@ -345,3 +310,3 @@ **Examples**

### `unevaluatedItems`
### `unevaluatedItems` <Badge text="NEW: draft 2019-09" />

@@ -419,3 +384,5 @@ The value of this keyword is a JSON Schema (can be a boolean).

**Please note**: `properties` keyword does not require that the properties mentioned in it are present in the object (see examples).
::: warning Please note
`properties` keyword does not require that the properties mentioned in it are present in the object (see examples).
:::

@@ -449,6 +416,7 @@ **Example**

**Please note**:
::: warning Please note
1. `patternProperties` keyword does not require that properties matching patterns are present in the object (see examples).
2. By default, Ajv does not allow schemas where patterns in `patternProperties` match any property name in `properties` keyword - that leads to unexpected validation results. It can be allowed with option `allowMatchingProperties`. See [Strict mode](./strict-mode.md)
:::

@@ -551,3 +519,3 @@ **Example**

### `dependencies`
### `dependencies` <Badge text="deprecated in draft 2019-09" type="warning" />

@@ -598,3 +566,3 @@ This keyword is deprecated. The same functionality is available with keywords `dependentRequired` and `dependentSchemas`.

### `dependentRequired`
### `dependentRequired` <Badge text="NEW: draft 2019-09" />

@@ -622,3 +590,3 @@ The value of this keyword should be a map with keys equal to data object properties. Each value in the map should be an array of unique property names.

### `dependentSchemas`
### `dependentSchemas` <Badge text="NEW: draft 2019-09" />

@@ -673,3 +641,3 @@ The value of the keyword should be a map with keys equal to data object properties. Each value in the map should be a JSON Schema.

### `unevaluatedProperties`
### `unevaluatedProperties` <Badge text="NEW: draft 2019-09" />

@@ -746,3 +714,3 @@ The value of this keyword is a JSON Schema (can be a boolean).

The same can be achieved with `enum` keyword using the array with one item. But `const` keyword is more than just a syntax sugar for `enum`. In combination with the [\$data reference](./validation.md#data-reference) it allows to define equality relations between different parts of the data. This cannot be achieved with `enum` keyword even with `$data` reference because `$data` cannot be used in place of one item - it can only be used in place of the whole array in `enum` keyword.
The same can be achieved with `enum` keyword using the array with one item. But `const` keyword is more than just a syntax sugar for `enum`. In combination with the [$data reference](./guide/combining-schemas.md#data-reference) it allows to define equality relations between different parts of the data. This cannot be achieved with `enum` keyword even with `$data` reference because `$data` cannot be used in place of one item - it can only be used in place of the whole array in `enum` keyword.

@@ -897,1 +865,17 @@ **Example**

- non-integers
## Metadata keywords
JSON Schema specification defines several metadata keywords that describe the schema itself but do not perform any validation.
- `title` and `description`: information about the data represented by that schema
- `$comment`: information for developers. With option `$comment` Ajv logs or passes the comment string to the user-supplied function. See [Options](./api.md#options).
- `default`: a default value of the data instance, see [Assigning defaults](#assigning-defaults).
- `examples`: an array of data instances. Ajv does not check the validity of these instances against the schema.
- `readOnly` and `writeOnly`: marks data-instance as read-only or write-only in relation to the source of the data (database, api, etc.).
- `contentEncoding`: [RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.1), e.g., "base64".
- `contentMediaType`: [RFC 2046](https://datatracker.ietf.org/doc/rfc2046/), e.g., "image/png".
::: warning Please note
Ajv does not implement validation of the keywords `examples`, `contentEncoding` and `contentMediaType` but it reserves them. If you want to create a plugin that implements any of them, it should remove these keywords from the instance.
:::

@@ -14,19 +14,4 @@ # JSON Type Definition

## Contents
[[toc]]
- [JTD schema forms](#jtd-schema-forms):
- [type](#type-schema-form) (for primitive values)
- [enum](#enum-schema-form)
- [elements](#elements-schema-form) (for arrays)
- [properties](#properties-schema-form) (for records)
- [discriminator](#discriminator-schema-form) (for tagged union of records)
- [values](#values-schema-form) (for dictionary)
- [ref](#ref-schema-form) (to reference a schema in definitions)
- [empty](#empty-schema-form) (for any data)
- [Extending JTD](#extending-jtd)
- [metadata](#metadata-schema-member)
- [union](#union-keyword)
- [user-defined keywords](#user-defined-keywords)
- [Validation errors](#validation-errors)
## JTD schema forms

@@ -45,3 +30,3 @@

### Type schema form
### Type form <Badge text="primitive values" />

@@ -78,3 +63,3 @@ This form defines a primitive value.

### Enum schema form
### Enum form

@@ -95,3 +80,3 @@ This form defines a string that can take one of the values from the list (the values in the list must be unique).

### Elements schema form
### Elements form <Badge text="arrays" />

@@ -120,3 +105,3 @@ This form defines a homogenous array of any size (possibly empty) with the elements that satisfy a given schema.

### Properties schema form
### Properties form <Badge text="objects" />

@@ -180,3 +165,3 @@ This form defines record (JSON object) that has defined required and optional properties.

### Discriminator schema form
### Discriminator form <Badge text="tagged union" />

@@ -239,3 +224,3 @@ This form defines discriminated (tagged) union of different record types.

### Values schema form
### Values form <Badge text="dictionary" />

@@ -264,3 +249,3 @@ This form defines a homogenous dictionary where the values of members satisfy a given schema.

### Ref schema form
### Ref form <Badge text="reference definitions" />

@@ -320,6 +305,78 @@ This form defines a reference to the schema that is present in the corresponding key in the `definitions` member of the root schema.

### Empty schema form
### Empty form <Badge text="any data" />
Empty JTD schema defines the data instance that can be of any type, including JSON `null` (even if `nullable` member is not present). It cannot have any member other than `nullable` and `metadata`.
## JTDSchemaType
The type `JTDSchemaType` can be used to validate that the written schema matches the type you expect to validate. This type is strict such that if typescript compiles, you should require no further type guards. The downside of this is that the types that `JTDSchemaType` can verify are limited to the types that JTD can verify. If a type doesn't verify, `JTDSchemaType` should resolve to `never`, throwing an error when you try to assign to it. This means that types like `1 | 2 | 3`, or general untagged unions (outside of unions of string literals) cannot be used with `JTDSchemaType`.
### Most Schemas
Most straightforward types should work with `JTDSchemaType`, e.g.
```typescript
interface MyType {
num: number
optionalStr?: string
nullableEnum: "v1.0" | "v1.2" | null
values: Record<string, number>
}
const schema: JTDSchemaType<MyType> = {
properties: {
num: {type: "float64"},
nullableEnum: {enum: ["v1.0", "v1.2"], nullable: true},
values: {values: {type: "int32"}},
},
optionalProperties: {
optionalStr: {type: "string"},
},
}
```
will compile. Using `schema` with AJV will guarantee type safety.
### Ref Schemas
Ref schemas are a little more advanced, because the types of every definition must be specified in advance.
A simple ref schema is relatively straightforward:
```typescript
const schema: JTDSchemaType<{val: number}, {num: number}> = {
definitions: {
num: {type: "float64"},
},
properties: {
val: {ref: "num"},
},
}
```
note that the type of all definitions was included as a second argument to `JTDSchemaType`.
This also works for recursive schemas:
```typescript
type LinkedList = {val: number; next?: LinkedList}
const schema: JTDSchemaType<LinkedList, {node: LinkedList}> = {
definitions: {
node: {
properties: {
val: {type: "float64"},
},
optionalProperties: {
next: {ref: "node"},
},
},
},
ref: "node",
}
```
### Notable Omissions
`JTDSchemaType` currently validats that if the schema compiles it will verify an accurate type, but there are a few places with potentially unexpected behavior.
`JTDSchemaType` doesn't verify the schema is correct. It won't reject schemas that definitions anywhere by the root, and it won't reject discriminator schemas that still define the descriminator in mapping properties. It also won't verify that enum schemas have every enum member as this isn't generally feasible in typescript yet.
## Extending JTD

@@ -335,3 +392,5 @@

**Please note**: Ajv-specific extension to JTD are likely to be unsupported by other tools, so while it may simplify adoption, it undermines the cross-platform objective of using JTD. While it is ok to put some human readable information in `metadata` member, it is recommended not to add any validation logic there (even if it is supported by Ajv).
::: warning Please note
Ajv-specific extension to JTD are likely to be unsupported by other tools, so while it may simplify adoption, it undermines the cross-platform objective of using JTD. While it is ok to put some human readable information in `metadata` member, it is recommended not to add any validation logic there (even if it is supported by Ajv).
:::

@@ -345,7 +404,9 @@ Additional restrictions that Ajv enforces on `metadata` schema member:

Ajv defines `union` keyword that is used in the schema that validates JTD schemas ([meta-schema](../lib/refs/jtd-schema.ts)).
Ajv defines `union` keyword that is used in the schema that validates JTD schemas ([meta-schema](https://github.com/ajv-validator/ajv/blob/master/lib/refs/jtd-schema.ts)).
This keyword can be used only inside `metadata` schema member.
**Please note**: This keyword is non-standard and it is not supported in other JTD tools, so it is recommended NOT to use this keyword in schemas for your data if you want them to be cross-platform.
::: warning Please note
This keyword is non-standard and it is not supported in other JTD tools, so it is recommended NOT to use this keyword in schemas for your data if you want them to be cross-platform.
:::

@@ -356,2 +417,8 @@ ### User-defined keywords

**Please note**: It is strongly recommended to only use it to simplify migration from JSON Schema to JTD and not to use non-standard keywords in the new schemas, as these keywords are not supported by any other tools.
::: warning Please note
It is strongly recommended to only use it to simplify migration from JSON Schema to JTD and not to use non-standard keywords in the new schemas, as these keywords are not supported by any other tools.
:::
## Validation errors
TODO
# User defined keywords
## Contents
[[toc]]
- Define keyword with:
- [code generation function](#define-keyword-with-code-generation-function) - used by all pre-defined keywords
- [validation function](#define-keyword-with-validation-function)
- [compilation function](#define-keyword-with-compilation-function)
- [macro function](#define-keyword-with-macro-function)
- [Schema compilation context](#schema-compilation-context)
- [Validation time variables](#validation-time-variables)
- [Ajv utilities](#ajv-utilities)
- [Defining keyword errors](#defining-keyword-errors)
## Common attributes of keyword definitions
### Common attributes of keyword definitions
The usual interface to define all keywords has these properties:

@@ -32,7 +22,7 @@

Keyword definitions may have additional optional properties - see [types](../lib/types/index.ts) and [KeywordCxt](../lib/compile/context.ts).
Keyword definitions may have additional optional properties - see [types](https://github.com/ajv-validator/ajv/blob/master/lib/types/index.ts) and [KeywordCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts).
### Define keyword with code generation function
### Define keyword with code generation function <Badge text="recommended" />
Starting from v7 Ajv uses [CodeGen module](../lib/compile/codegen/index.ts) for all pre-defined keywords - see [codegen.md](./codegen.md) for details.
Starting from v7 Ajv uses [CodeGen module](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts) for all pre-defined keywords - see [codegen.md](./codegen.md) for details.

@@ -65,3 +55,3 @@ This is the best approach for user defined keywords:

schemaType: "boolean",
// $data: true // to support [$data reference](./validation.md#data-reference), ...
// $data: true // to support [$data reference](./guide/combining-schemas.md#data-reference), ...
code(cxt: KeywordCxt) {

@@ -103,5 +93,5 @@ const {data, schema} = cxt

You can review pre-defined Ajv keywords in [validation](../lib/validation) folder for more advanced examples - it is much easier to define code generation keywords than it was in the previous version of Ajv.
You can review pre-defined Ajv keywords in [validation](https://github.com/ajv-validator/ajv/blob/master/lib/validation) folder for more advanced examples - it is much easier to define code generation keywords than it was in the previous version of Ajv.
See [KeywordCxt](../lib/compile/context.ts) and [SchemaCxt](../lib/compile/index.ts) type definitions for more information about properties you can use in your keywords.
See [KeywordCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts) and [SchemaCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/index.ts) type definitions for more information about properties you can use in your keywords.

@@ -142,3 +132,3 @@ ### Define keyword with "validate" function

- defining keywords where the schema is a value used in some expression.
- defining keywords that support [\$data reference](./validation.md#data-reference) - in this case `validate` or `code` function is required, either as the only option or in addition to `compile` or `macro`.
- defining keywords that support [\$data reference](./guide/combining-schemas.md#data-reference) - in this case `validate` or `code` function is required, either as the only option or in addition to `compile` or `macro`.

@@ -172,3 +162,5 @@ Example: `constant` keyword (a synonym for draft-06 keyword `const`, it is equivalent to `enum` keyword with one item):

**Please note:** If the keyword does not define errors (see [Reporting errors](./api.md#reporting-errors)) pass `errors: false` in its definition; it will make generated code more efficient.
::: tip Please note
If the keyword does not define errors (see [Reporting errors](./api.md#reporting-errors)) pass `errors: false` in its definition; it will make generated code more efficient.
:::

@@ -259,7 +251,7 @@ To add asynchronous keyword pass `async: true` in its definition.

Schema compilation context [SchemaCxt](../lib/compile/index.ts) is available in property `it` of [KeywordCxt](../lib/compile/context.ts) (and it is also the 3rd parameter of `compile` and `macro` keyword functions). See types in the source code on the properties you can use in this object.
Schema compilation context [SchemaCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/index.ts) is available in property `it` of [KeywordCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts) (and it is also the 3rd parameter of `compile` and `macro` keyword functions). See types in the source code on the properties you can use in this object.
## Validation time variables
All function scoped variables available during validation are defined in [names](../lib/compile/names.ts).
All function scoped variables available during validation are defined in [names](https://github.com/ajv-validator/ajv/blob/master/lib/compile/names.ts).

@@ -266,0 +258,0 @@ ## Reporting errors

@@ -5,8 +5,3 @@ # Security considerations

- [Security contact](#security-contact)
- [Untrusted schemas](#untrusted-schemas)
- [Circular references in objects](#circular-references-in-javascript-objects)
- [Trusted schemas](#security-risks-of-trusted-schemas)
- [ReDoS attack](#redos-attack)
- [Content Security Policy](#content-security-policy)
[[toc]]

@@ -47,5 +42,7 @@ ## Security contact

**Please note**: The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors).
::: danger Please note
The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors).
:::
You can validate your JSON schemas against [this meta-schema](../lib/refs/json-schema-secure.json) to check that these recommendations are followed:
You can validate your JSON schemas against [this meta-schema](https://github.com/ajv-validator/ajv/blob/master/lib/refs/json-schema-secure.json) to check that these recommendations are followed:

@@ -63,3 +60,5 @@ ```javascript

**Please note**: following all these recommendation is not a guarantee that validation of untrusted data is safe - it can still lead to some undesirable results.
::: danger Please note
Following all these recommendation is not a guarantee that validation using of untrusted data is safe - it can still lead to some undesirable results.
:::

@@ -72,4 +71,8 @@ ## ReDoS attack

**Please note**: some formats that [ajv-formats](https://github.com/ajv-validator/ajv-formats) package implements use [regular expressions](https://github.com/ajv-validator/ajv-formats/blob/master/src/formats.ts) that can be vulnerable to ReDoS attack, so if you use Ajv to validate data from untrusted sources **it is strongly recommended** to consider the following:
::: warning Please note
Some formats that [ajv-formats](https://github.com/ajv-validator/ajv-formats) package implements use [regular expressions](https://github.com/ajv-validator/ajv-formats/blob/master/src/formats.ts) that can be vulnerable to ReDoS attack.
:::
If you use Ajv to validate data from untrusted sources **it is strongly recommended** to consider the following:
- making assessment of "format" implementations in [ajv-formats](https://github.com/ajv-validator/ajv-formats).

@@ -86,4 +89,6 @@ - passing `"fast"` option to ajv-formats plugin (see its docs) that simplifies some of the regular expressions (although it does not guarantee that they are safe).

**Please note**: `unsafe-eval` is NOT recommended in a secure CSP[[1]](https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval), as it has the potential to open the document to cross-site scripting (XSS) attacks.
::: warning Please note
`unsafe-eval` is NOT recommended in a secure CSP[[1]](https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval), as it has the potential to open the document to cross-site scripting (XSS) attacks.
:::
In order to use Ajv without relaxing CSP, you can [compile the schemas using CLI](https://github.com/ajv-validator/ajv-cli#compile-schemas) or programmatically in your build code - see [Standalone validation code](./standalone.md). Compiled JavaScript file can export one or several validation functions that have the same code as the schemas compiled at runtime.
# Standalone validation code
[[toc]]
Ajv supports generating standalone modules with exported validation function(s), with one default export or multiple named exports, that are pre-compiled and can be used without Ajv. It is useful for several reasons:

@@ -79,3 +81,3 @@

- only `code` and `macro` user-defined keywords are supported (see [User defined keywords](./keywords.md)).
- when `code` keywords define variables in shared scope using `gen.scopeValue`, they must provide `code` property with the code snippet. See source code of pre-defined keywords for examples in [vocabularies folder](../lib/vocabularies).
- when `code` keywords define variables in shared scope using `gen.scopeValue`, they must provide `code` property with the code snippet. See source code of pre-defined keywords for examples in [vocabularies folder](https://github.com/ajv-validator/ajv/blob/master/lib/vocabularies).
- if formats are used in standalone code, ajv option `code.formats` should contain the code snippet that will evaluate to an object with all used formats definition - it can be a call to `require("...")` with the correct path (relative to the location of saved module):

@@ -82,0 +84,0 @@

@@ -7,19 +7,3 @@ # Strict mode

- [JSON Type Definition schemas](#json-type-definition-schemas)
- [JSON Schema schemas](#json-schema-schemas)
- [Prohibit ignored keywords](#prohibit-ignored-keywords)
- unknown keywords
- ignored "additionalItems" keyword
- ignored "if", "then", "else" keywords
- ignored "contains", "maxContains" and "minContains" keywords
- unknown formats
- ignored defaults
- [Prevent unexpected validation](#prevent-unexpected-validation)
- overlap between "properties" and "patternProperties" keywords (also `allowMatchingProperties` option)
- unconstrained tuples (also `strictTuples` option)
- [Strict types](#strict-types) (also `strictTypes` option)
- union types (also `allowUnionTypes` option)
- contradictory types
- require applicable types
- [Strict number validation](#strict-number-validation)
[[toc]]

@@ -45,3 +29,3 @@ ## JSON Type Definition schemas

#### Prohibit unknown keywords
#### Unknown keywords

@@ -67,3 +51,3 @@ JSON Schema [section 6.5](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-6.5) requires to ignore unknown keywords. The motivation is to increase cross-platform portability of schemas, so that implementations that do not support certain keywords can still do partial validation.

#### Prohibit ignored "additionalItems" keyword
#### Ignored "additionalItems" keyword

@@ -74,3 +58,3 @@ JSON Schema section [9.3.1.2](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.1.2) requires to ignore "additionalItems" keyword if "items" keyword is absent or if it is not an array of items. This is inconsistent with the interaction of "additionalProperties" and "properties", and may cause unexpected results.

#### Prohibit ignored "if", "then", "else" keywords
#### Ignored "if", "then", "else" keywords

@@ -81,3 +65,3 @@ JSON Schema section [9.2.2](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.2) requires to ignore "if" (only annotations are collected) if both "then" and "else" are absent, and ignore "then"/"else" if "if" is absent.

#### Prohibit ignored "contains", "maxContains" and "minContains" keywords
#### Ignored "contains", "maxContains" and "minContains" keywords

@@ -90,5 +74,5 @@ JSON Schema sections [6.4.4, 6.4.5](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.6.4.4) require to ignore keywords "maxContains" and "minContains" if "contains" keyword is absent.

#### Prohibit unknown formats
#### Unknown formats
By default unknown formats throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./validation.md#data-reference)). It is possible to opt out of format validation completely with options `validateFormats: false`. You can define all known formats with `addFormat` method or `formats` option - to have some format ignored pass `true` as its definition:
By default unknown formats throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./guide/combining-schemas.md#data-reference)). It is possible to opt out of format validation completely with options `validateFormats: false`. You can define all known formats with `addFormat` method or `formats` option - to have some format ignored pass `true` as its definition:

@@ -101,11 +85,11 @@ ```javascript

Standard JSON Schema formats are provided in [ajv-formats](https://github.com/ajv-validator/ajv-formats) package - see [Formats](./validation.md#formats) section.
Standard JSON Schema formats are provided in [ajv-formats](https://github.com/ajv-validator/ajv-formats) package - see [Formats](./guide/formats) section.
#### Prohibit ignored defaults
#### Ignored defaults
With `useDefaults` option Ajv modifies validated data by assigning defaults from the schema, but there are different limitations when the defaults can be ignored (see [Assigning defaults](./validation.md#assigning-defaults)). In strict mode Ajv fails schema compilation if such defaults are used in the schema.
With `useDefaults` option Ajv modifies validated data by assigning defaults from the schema, but there are different limitations when the defaults can be ignored (see [Assigning defaults](./guide/modifying-data.md#assigning-defaults)). In strict mode Ajv fails schema compilation if such defaults are used in the schema.
### Prevent unexpected validation
#### Prohibit overlap between "properties" and "patternProperties" keywords
#### Overlap between "properties" and "patternProperties" keywords <Badge text="allowMatchingProperties option"/>

@@ -120,4 +104,14 @@ The expectation of users (see #196, #286) is that "patternProperties" only apply to properties not already defined in "properties" keyword, but JSON Schema section [9.3.2](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2) defines these two keywords as independent. It means that to some properties two subschemas can be applied - one defined in "properties" keyword and another defined in "patternProperties" for the pattern matching this property.

#### Prohibit unconstrained tuples
#### Defined required properties <Badge text="strictRequired option" />
With option `strictRequired` set to `"log"` or `true` Ajv logs warning or throws exception if the property used in "required" keyword is not defined in "properties" keyword in the same or some parent schema relating to the same object (data instance).
By default this option is disabled.
::: warning Please note
there are certain scenarios when property defined in the parent schema will not be taken into account.
:::
#### Unconstrained tuples <Badge text="strictTuples option" />
Ajv also logs a warning if "items" is an array (for schema that defines a tuple) but neither "minItems" nor "additionalItems"/"maxItems" keyword is present (or have a wrong value):

@@ -151,7 +145,7 @@

### Strict types
### Strict types <Badge text="strictTypes option" />
An additional option `strictTypes` ("log" by default) imposes additional restrictions on how type keyword is used:
#### Prohibit union types
#### Union types <Badge text="allowUnionTypes option" />

@@ -242,3 +236,3 @@ With `strictTypes` option "type" keywords with multiple types (other than with "null") are prohibited.

#### Prohibit contradictory types
#### Contradictory types

@@ -269,3 +263,5 @@ Subschemas can apply to the same data instance, and it is possible to have contradictory type keywords - it usually indicate some mistake. For example:

**Please note**: type "number" can be narrowed to "integer", the opposite would violate `strictTypes`.
::: warning Please note
Type "number" can be narrowed to "integer", the opposite would violate `strictTypes`.
:::

@@ -272,0 +268,0 @@ #### Require applicable types

@@ -18,2 +18,3 @@ export {

AsyncValidateFunction,
SchemaValidateFunction,
ErrorObject,

@@ -35,3 +36,3 @@ ErrorNoParams,

import draft7Vocabularies from "./vocabularies/draft7"
import draft7MetaSchema = require("./refs/json-schema-draft-07.json")
import * as draft7MetaSchema from "./refs/json-schema-draft-07.json"

@@ -38,0 +39,0 @@ const META_SUPPORT_DATA = ["/properties"]

@@ -24,2 +24,3 @@ import type {ScopeValueSets, NameValue, ValueScope, ValueScopeName} from "./scope"

AND: new _Code("&&"),
ADD: new _Code("+"),
}

@@ -66,7 +67,3 @@

class Assign extends Node {
constructor(
private readonly lhs: Code,
private rhs: SafeExpr,
private readonly sideEffects?: boolean
) {
constructor(readonly lhs: Code, public rhs: SafeExpr, private readonly sideEffects?: boolean) {
super()

@@ -91,2 +88,12 @@ }

class AssignOp extends Assign {
constructor(lhs: Code, private readonly op: Code, rhs: SafeExpr, sideEffects?: boolean) {
super(lhs, rhs, sideEffects)
}
render({_n}: CGOptions): string {
return `${this.lhs} ${this.op}= ${this.rhs};` + _n
}
}
class Label extends Node {

@@ -514,2 +521,7 @@ readonly names: UsedNames = {}

// `+=` code
add(lhs: Code, rhs: SafeExpr): CodeGen {
return this._leafNode(new AssignOp(lhs, operators.ADD, rhs))
}
// appends passed SafeExpr to code or executes Block

@@ -516,0 +528,0 @@ code(c: Block | SafeExpr): CodeGen {

@@ -17,3 +17,3 @@ import type {

import {validateFunctionCode} from "./validate"
import URI = require("uri-js")
import * as URI from "uri-js"
import {JSONType} from "./rules"

@@ -36,2 +36,3 @@

dataTypes: JSONType[] // data types applied to the current part of data instance
definedProperties: Set<string> // set of properties to keep track of for required checks
readonly topSchemaRef: Code

@@ -84,2 +85,6 @@ readonly validateName: Name

validateName?: ValueScopeName
serialize?: (data: unknown) => string
serializeName?: ValueScopeName
parse?: (data: string) => unknown
parseName?: ValueScopeName

@@ -132,2 +137,3 @@ constructor(env: SchemaEnvArgs) {

dataTypes: [],
definedProperties: new Set<string>(),
topSchemaRef: gen.scopeValue(

@@ -223,3 +229,3 @@ "schema",

// Index of schema compilation in the currently compiled list
function getCompilingSchema(this: Ajv, schEnv: SchemaEnv): SchemaEnv | void {
export function getCompilingSchema(this: Ajv, schEnv: SchemaEnv): SchemaEnv | void {
for (const sch of this._compilations) {

@@ -226,0 +232,0 @@ if (sameSchemaEnv(sch, schEnv)) return sch

@@ -20,4 +20,9 @@ import {Name} from "./codegen"

scope: new Name("scope"),
// JTD serialize/parse name for JSON string and position
json: new Name("json"),
jsonPos: new Name("jsonPos"),
jsonLen: new Name("jsonLen"),
jsonPart: new Name("jsonPart"),
}
export default names
import type {AnySchema, AnySchemaObject} from "../types"
import type Ajv from "../ajv"
import {eachItem} from "./util"
import equal = require("fast-deep-equal")
import traverse = require("json-schema-traverse")
import URI = require("uri-js")
import * as equal from "fast-deep-equal"
import * as traverse from "json-schema-traverse"
import * as URI from "uri-js"

@@ -8,0 +8,0 @@ // the hash of local references inside the schema (created by getSchemaRefs), used for inline resolution

@@ -45,2 +45,3 @@ import type {AnySchema} from "../types"

dataTypes: JSONType[]
definedProperties: Set<string>
propertyName: Name

@@ -135,2 +136,3 @@ dataPropType: Type

subschema.dataTypes = []
it.definedProperties = new Set<string>()
subschema.parentData = it.data

@@ -137,0 +139,0 @@ subschema.dataNames = [...it.dataNames, _nextData]

@@ -0,1 +1,3 @@

import {_} from "./codegen"
const DATE_TIME = /^(\d\d\d\d)-(\d\d)-(\d\d)(?:t|\s)(\d\d):(\d\d):(\d\d)(?:\.\d+)?(?:z|([+-]\d\d)(?::?(\d\d))?)$/i

@@ -28,1 +30,3 @@ const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

}
validTimestamp.code = _`require("ajv/dist/compile/timestamp").default`

@@ -170,1 +170,8 @@ import type {AnySchema, EvaluatedProperties, EvaluatedItems} from "../types"

}
export function func(gen: CodeGen, f: {code: Code}): Name {
return gen.scopeValue("func", {
ref: f,
code: f.code,
})
}

@@ -34,2 +34,3 @@ export {

export {JSONSchemaType} from "./types/json-schema"
export {JTDSchemaType} from "./types/jtd-schema"
export {_, str, stringify, nil, Name, Code, CodeGen, CodeGenOptions} from "./compile/codegen"

@@ -54,2 +55,3 @@

import type {JSONSchemaType} from "./types/json-schema"
import type {JTDSchemaType} from "./types/jtd-schema"
import {ValidationError, MissingRefError} from "./compile/error_classes"

@@ -63,3 +65,3 @@ import {getRules, ValidationRules, Rule, RuleGroup, JSONType} from "./compile/rules"

import $dataRefSchema = require("./refs/data.json")
import * as $dataRefSchema from "./refs/data.json"

@@ -69,2 +71,4 @@ const META_IGNORE_OPTIONS: (keyof Options)[] = ["removeAdditional", "useDefaults", "coerceTypes"]

"validate",
"serialize",
"parse",
"wrapper",

@@ -89,2 +93,3 @@ "root",

strictTuples?: boolean | "log"
strictRequired?: boolean | "log"
allowMatchingProperties?: boolean // disables a strict mode restriction

@@ -302,2 +307,5 @@ allowUnionTypes?: boolean

validate<T>(schema: Schema | JSONSchemaType<T> | string, data: unknown): data is T
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
validate<T>(schema: JTDSchemaType<T>, data: unknown): data is T
validate<T>(schema: AsyncSchema, data: unknown | T): Promise<T>

@@ -325,2 +333,5 @@ validate<T>(schemaKeyRef: AnySchema | string, data: unknown): data is T | Promise<T>

compile<T = unknown>(schema: Schema | JSONSchemaType<T>, _meta?: boolean): ValidateFunction<T>
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
compile<T = unknown>(schema: JTDSchemaType<T>, _meta?: boolean): ValidateFunction<T>
compile<T = unknown>(schema: AsyncSchema, _meta?: boolean): AsyncValidateFunction<T>

@@ -341,2 +352,5 @@ compile<T = unknown>(schema: AnySchema, _meta?: boolean): AnyValidateFunction<T>

): Promise<ValidateFunction<T>>
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
compileAsync<T = unknown>(schema: JTDSchemaType<T>, _meta?: boolean): Promise<ValidateFunction<T>>
compileAsync<T = unknown>(schema: AsyncSchema, meta?: boolean): Promise<AsyncValidateFunction<T>>

@@ -633,3 +647,3 @@ // eslint-disable-next-line @typescript-eslint/unified-signatures

private _addSchema(
_addSchema(
schema: AnySchema,

@@ -636,0 +650,0 @@ meta?: boolean,

@@ -20,2 +20,3 @@ export {

ErrorNoParams,
JTDParser,
} from "./types"

@@ -30,6 +31,11 @@

import type {AnySchemaObject} from "./types"
import type {AnySchemaObject, SchemaObject, JTDParser} from "./types"
import type {JTDSchemaType, JTDDataType} from "./types/jtd-schema"
export {JTDSchemaType, JTDDataType}
import AjvCore, {CurrentOptions} from "./core"
import jtdVocabulary from "./vocabularies/jtd"
import jtdMetaSchema from "./refs/jtd-schema"
import compileSerializer from "./compile/jtd/serialize"
import compileParser from "./compile/jtd/parse"
import {SchemaEnv} from "./compile"

@@ -92,2 +98,34 @@ // const META_SUPPORT_DATA = ["/properties"]

}
compileSerializer<T = unknown>(schema: SchemaObject): (data: T) => string
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
compileSerializer<T = unknown>(schema: JTDSchemaType<T>): (data: T) => string
compileSerializer<T = unknown>(schema: SchemaObject): (data: T) => string {
const sch = this._addSchema(schema)
return sch.serialize || this._compileSerializer(sch)
}
compileParser<T = unknown>(schema: SchemaObject): JTDParser<T>
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
compileParser<T = unknown>(schema: JTDSchemaType<T>): JTDParser<T>
compileParser<T = unknown>(schema: SchemaObject): JTDParser<T> {
const sch = this._addSchema(schema)
return (sch.parse || this._compileParser(sch)) as JTDParser<T>
}
private _compileSerializer<T>(sch: SchemaEnv): (data: T) => string {
compileSerializer.call(this, sch, (sch.schema as AnySchemaObject).definitions || {})
/* istanbul ignore if */
if (!sch.serialize) throw new Error("ajv implementation error")
return sch.serialize
}
private _compileParser(sch: SchemaEnv): JTDParser {
compileParser.call(this, sch, (sch.schema as AnySchemaObject).definitions || {})
/* istanbul ignore if */
if (!sch.parse) throw new Error("ajv implementation error")
return sch.parse
}
}
import type Ajv from "../../core"
import type {AnySchemaObject} from "../../types"
import metaSchema = require("./schema.json")
import metaApplicator = require("./meta/applicator.json")
import metaContent = require("./meta/content.json")
import metaCore = require("./meta/core.json")
import metaFormat = require("./meta/format.json")
import metaMetadata = require("./meta/meta-data.json")
import metaValidation = require("./meta/validation.json")
import * as metaSchema from "./schema.json"
import * as metaApplicator from "./meta/applicator.json"
import * as metaContent from "./meta/content.json"
import * as metaCore from "./meta/core.json"
import * as metaFormat from "./meta/format.json"
import * as metaMetadata from "./meta/meta-data.json"
import * as metaValidation from "./meta/validation.json"

@@ -11,0 +11,0 @@ const META_SUPPORT_DATA = ["/properties"]

import Ajv, {AnySchema, AnyValidateFunction, ErrorObject} from "../core"
import standaloneCode from "."
import requireFromString = require("require-from-string")
import * as requireFromString from "require-from-string"

@@ -5,0 +5,0 @@ export default class AjvPack {

@@ -56,2 +56,8 @@ import type {CodeGen, Code, Name, ScopeValueSets, ValueScopeName} from "../compile/codegen"

export interface JTDParser<T = unknown> {
(json: string): T | undefined
message?: string
position?: number
}
export type EvaluatedProperties = {[K in string]?: true} | true

@@ -100,3 +106,3 @@

allowUndefined?: boolean // used for keywords that can be invoked by other keywords, not being present in the schema
$data?: boolean // keyword supports [$data reference](../../docs/validation.md#data-reference)
$data?: boolean // keyword supports [$data reference](../../docs/guide/combining-schemas.md#data-reference)
implements?: string[] // other schema keywords that this keyword implements

@@ -103,0 +109,0 @@ before?: string // keyword should be executed before this keyword (should be applicable to the same type)

@@ -37,3 +37,3 @@ /* eslint-disable @typescript-eslint/no-empty-interface */

items: {
[K in keyof T]-?: JSONSchemaType<T[K]> & Nullable<T[K]>
readonly [K in keyof T]-?: JSONSchemaType<T[K]> & Nullable<T[K]>
} & {length: T["length"]}

@@ -63,3 +63,3 @@ minItems: T["length"]

// it only asserts that optional cannot be listed
required: _partial extends true ? (keyof T)[] : RequiredMembers<T>[]
required: _partial extends true ? Readonly<(keyof T)[]> : Readonly<RequiredMembers<T>[]>
additionalProperties?: boolean | JSONSchemaType<T[string]>

@@ -70,4 +70,4 @@ unevaluatedProperties?: boolean | JSONSchemaType<T[string]>

propertyNames?: JSONSchemaType<string>
dependencies?: {[K in keyof T]?: (keyof T)[] | PartialSchema<T>}
dependentRequired?: {[K in keyof T]?: (keyof T)[]}
dependencies?: {[K in keyof T]?: Readonly<(keyof T)[]> | PartialSchema<T>}
dependentRequired?: {[K in keyof T]?: Readonly<(keyof T)[]>}
dependentSchemas?: {[K in keyof T]?: PartialSchema<T>}

@@ -91,5 +91,5 @@ minProperties?: number

}
allOf?: PartialSchema<T>[]
anyOf?: PartialSchema<T>[]
oneOf?: PartialSchema<T>[]
allOf?: Readonly<PartialSchema<T>[]>
anyOf?: Readonly<PartialSchema<T>[]>
oneOf?: Readonly<PartialSchema<T>[]>
if?: PartialSchema<T>

@@ -105,7 +105,7 @@ then?: PartialSchema<T>

type PropertiesSchema<T> = {
export type PropertiesSchema<T> = {
[K in keyof T]-?: (JSONSchemaType<T[K]> & Nullable<T[K]>) | {$ref: string}
}
type RequiredMembers<T> = {
export type RequiredMembers<T> = {
[K in keyof T]-?: undefined extends T[K] ? never : K

@@ -118,3 +118,3 @@ }[keyof T]

const?: never // any non-null value would fail `const: null`, `null` would fail any other value in const
enum?: (T | null)[] // `null` must be explicitly included in "enum" for `null` to pass
enum?: Readonly<(T | null)[]> // `null` must be explicitly included in "enum" for `null` to pass
default?: T | null

@@ -124,4 +124,4 @@ }

const?: T
enum?: T[]
enum?: Readonly<T[]>
default?: T
}

@@ -8,3 +8,3 @@ import type {

} from "../../types"
import {allSchemaProperties, usePattern} from "../code"
import {allSchemaProperties, usePattern, isOwnProperty} from "../code"
import {_, nil, or, not, Code, Name} from "../../compile/codegen"

@@ -56,9 +56,4 @@ import N from "../../compile/names"

// TODO maybe an option instead of hard-coded 8?
const hasProp = gen.scopeValue("func", {
// eslint-disable-next-line @typescript-eslint/unbound-method
ref: Object.prototype.hasOwnProperty,
code: _`Object.prototype.hasOwnProperty`,
})
const propsSchema = schemaRefOrVal(it, parentSchema.properties, "properties")
definedProp = _`${hasProp}.call(${propsSchema}, ${key})`
definedProp = isOwnProperty(gen, propsSchema as Code, key)
} else if (props.length) {

@@ -65,0 +60,0 @@ definedProp = or(...props.map((p) => _`${key} === ${p}`))

@@ -75,3 +75,3 @@ import type {

if (deps.length === 0) continue
const hasProperty = propertyInData(data, prop, it.opts.ownProperties)
const hasProperty = propertyInData(gen, data, prop, it.opts.ownProperties)
cxt.setParams({

@@ -102,3 +102,3 @@ property: prop,

gen.if(
propertyInData(data, prop, it.opts.ownProperties),
propertyInData(gen, data, prop, it.opts.ownProperties),
() => {

@@ -105,0 +105,0 @@ const schCxt = cxt.subschema({keyword, schemaProp: prop}, valid)

@@ -17,2 +17,5 @@ import type {CodeKeywordDefinition} from "../../types"

const allProps = allSchemaProperties(schema)
for (const prop of allProps) {
it.definedProperties.add(prop)
}
if (it.opts.unevaluated && allProps.length && it.props !== true) {

@@ -29,3 +32,3 @@ it.props = mergeEvaluated.props(gen, toHash(allProps), it.props)

} else {
gen.if(propertyInData(data, prop, it.opts.ownProperties))
gen.if(propertyInData(gen, data, prop, it.opts.ownProperties))
applyPropertySchema(prop)

@@ -35,2 +38,3 @@ if (!it.allErrors) gen.else().var(valid, true)

}
cxt.it.definedProperties.add(prop)
cxt.ok(valid)

@@ -37,0 +41,0 @@ }

@@ -11,3 +11,3 @@ import type {AnySchema, SchemaMap} from "../types"

const {gen, data, it} = cxt
gen.if(noPropertyInData(data, prop, it.opts.ownProperties), () => {
gen.if(noPropertyInData(gen, data, prop, it.opts.ownProperties), () => {
cxt.setParams({missingProperty: _`${prop}`}, true)

@@ -19,3 +19,3 @@ cxt.error()

export function checkMissingProp(
{data, it: {opts}}: KeywordCxt,
{gen, data, it: {opts}}: KeywordCxt,
properties: string[],

@@ -26,3 +26,4 @@ missing: Name

...properties.map(
(prop) => _`${noPropertyInData(data, prop, opts.ownProperties)} && (${missing} = ${prop})`
(prop) =>
_`${noPropertyInData(gen, data, prop, opts.ownProperties)} && (${missing} = ${prop})`
)

@@ -37,12 +38,26 @@ )

function isOwnProperty(data: Name, property: Name | string): Code {
return _`Object.prototype.hasOwnProperty.call(${data}, ${property})`
export function hasPropFunc(gen: CodeGen): Name {
return gen.scopeValue("func", {
// eslint-disable-next-line @typescript-eslint/unbound-method
ref: Object.prototype.hasOwnProperty,
code: _`Object.prototype.hasOwnProperty`,
})
}
export function propertyInData(data: Name, property: Name | string, ownProperties?: boolean): Code {
export function isOwnProperty(gen: CodeGen, data: Name, property: Name | string): Code {
return _`${hasPropFunc(gen)}.call(${data}, ${property})`
}
export function propertyInData(
gen: CodeGen,
data: Name,
property: Name | string,
ownProperties?: boolean
): Code {
const cond = _`${data}${getProperty(property)} !== undefined`
return ownProperties ? _`${cond} && ${isOwnProperty(data, property)}` : cond
return ownProperties ? _`${cond} && ${isOwnProperty(gen, data, property)}` : cond
}
export function noPropertyInData(
gen: CodeGen,
data: Name,

@@ -53,3 +68,3 @@ property: Name | string,

const cond = _`${data}${getProperty(property)} === undefined`
return ownProperties ? _`${cond} || !${isOwnProperty(data, property)}` : cond
return ownProperties ? _`${cond} || !${isOwnProperty(gen, data, property)}` : cond
}

@@ -56,0 +71,0 @@

import type {CodeKeywordDefinition} from "../../types"
import type KeywordCxt from "../../compile/context"
import {propertyInData, allSchemaProperties} from "../code"
import {propertyInData, allSchemaProperties, isOwnProperty} from "../code"
import {alwaysValidSchema, schemaRefOrVal} from "../../compile/util"

@@ -66,3 +66,3 @@ import {_, and, Code, Name} from "../../compile/codegen"

gen.if(
propertyInData(data, prop, it.opts.ownProperties),
propertyInData(gen, data, prop, it.opts.ownProperties),
() => applyPropertySchema(prop, keyword, _valid),

@@ -120,8 +120,3 @@ missingProperty

const propsSchema = schemaRefOrVal(it, parentSchema[keyword], keyword)
const hasProp = gen.scopeValue("func", {
// eslint-disable-next-line @typescript-eslint/unbound-method
ref: Object.prototype.hasOwnProperty,
code: _`Object.prototype.hasOwnProperty`,
})
additional = _`!${hasProp}.call(${propsSchema}, ${key})`
additional = isOwnProperty(gen, propsSchema as Code, key)
} else if (props.length) {

@@ -128,0 +123,0 @@ additional = and(...props.map((p) => _`${key} !== ${p}`))

@@ -60,13 +60,13 @@ import type {CodeKeywordDefinition, AnySchemaObject} from "../../types"

}
function hasRef(schema: AnySchemaObject): boolean {
for (const key in schema) {
let sch: AnySchemaObject
if (key === "ref" || (typeof (sch = schema[key]) == "object" && hasRef(sch))) return true
}
return false
}
},
}
export function hasRef(schema: AnySchemaObject): boolean {
for (const key in schema) {
let sch: AnySchemaObject
if (key === "ref" || (typeof (sch = schema[key]) == "object" && hasRef(sch))) return true
}
return false
}
export default def

@@ -5,13 +5,14 @@ import type {CodeKeywordDefinition} from "../../types"

import validTimestamp from "../../compile/timestamp"
import {func} from "../../compile/util"
import {checkMetadata} from "./metadata"
type IntType = "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32"
export type IntType = "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32"
const intRange: {[T in IntType]: [number, number]} = {
int8: [-128, 127],
uint8: [0, 255],
int16: [-32768, 32767],
uint16: [0, 65535],
int32: [-2147483648, 2147483647],
uint32: [0, 4294967295],
export const intRange: {[T in IntType]: [number, number, number]} = {
int8: [-128, 127, 3],
uint8: [0, 255, 3],
int16: [-32768, 32767, 5],
uint16: [0, 65535, 5],
int32: [-2147483648, 2147483647, 10],
uint32: [0, 4294967295, 10],
}

@@ -32,6 +33,3 @@

case "timestamp": {
const vts = gen.scopeValue("func", {
ref: validTimestamp,
code: _`require("ajv/dist/compile/timestamp").default`,
})
const vts = func(gen, validTimestamp)
cond = _`${data} instanceof Date || (typeof ${data} == "string" && ${vts}(${data}))`

@@ -38,0 +36,0 @@ break

import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type KeywordCxt from "../../compile/context"
import {_} from "../../compile/codegen"
import equal = require("fast-deep-equal")
import * as equal from "fast-deep-equal"

@@ -6,0 +6,0 @@ export type ConstError = ErrorObject<"const", {allowedValue: any}>

import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type KeywordCxt from "../../compile/context"
import {_, or, Name, Code} from "../../compile/codegen"
import equal = require("fast-deep-equal")
import * as equal from "fast-deep-equal"

@@ -6,0 +6,0 @@ export type EnumError = ErrorObject<"enum", {allowedValues: any[]}, any[] | {$data: string}>

@@ -11,2 +11,3 @@ import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"

import {_, str, nil, not, Name, Code} from "../../compile/codegen"
import {checkStrictMode} from "../../compile/validate"

@@ -38,2 +39,14 @@ export type RequiredError = ErrorObject<

if (opts.strictRequired) {
const props = cxt.parentSchema.properties
const {definedProperties} = cxt.it
for (const requiredKey of schema) {
if (props?.[requiredKey] === undefined && !definedProperties.has(requiredKey)) {
const schemaPath = it.schemaEnv.baseId + it.errSchemaPath
const msg = `required property "${requiredKey}" is not defined at "${schemaPath}" (strictRequired)`
checkStrictMode(it, msg, it.opts.strictRequired)
}
}
}
function allErrorsMode(): void {

@@ -65,3 +78,3 @@ if (useLoop || $data) {

cxt.setParams({missingProperty: prop})
gen.if(noPropertyInData(data, prop, opts.ownProperties), () => cxt.error())
gen.if(noPropertyInData(gen, data, prop, opts.ownProperties), () => cxt.error())
})

@@ -76,3 +89,3 @@ }

() => {
gen.assign(valid, propertyInData(data, missing, opts.ownProperties))
gen.assign(valid, propertyInData(gen, data, missing, opts.ownProperties))
gen.if(not(valid), () => {

@@ -79,0 +92,0 @@ cxt.error()

@@ -5,3 +5,3 @@ import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"

import {_, str, Name} from "../../compile/codegen"
import equal = require("fast-deep-equal")
import * as equal from "fast-deep-equal"

@@ -8,0 +8,0 @@ export type UniqueItemsError = ErrorObject<

{
"name": "ajv",
"version": "7.1.1",
"version": "7.2.0",
"description": "Another JSON Schema Validator",

@@ -16,4 +16,4 @@ "main": "dist/ajv.js",

"eslint": "eslint \"lib/**/*.ts\" \"spec/**/*.*s\" scripts --ignore-pattern spec/JSON-Schema-Test-Suite",
"prettier:write": "prettier --write \"./**/*.{md,json,yaml,js,ts}\"",
"prettier:check": "prettier --list-different \"./**/*.{md,json,yaml,js,ts}\"",
"prettier:write": "prettier --write \"./**/*.{json,yaml,js,ts}\"",
"prettier:check": "prettier --list-different \"./**/*.{json,yaml,js,ts}\"",
"test-spec": "cross-env TS_NODE_PROJECT=spec/tsconfig.json mocha -r ts-node/register \"spec/**/*.spec.{ts,js}\" -R dot",

@@ -31,3 +31,6 @@ "test-codegen": "nyc cross-env TS_NODE_PROJECT=spec/tsconfig.json mocha -r ts-node/register 'spec/codegen.spec.ts' -R spec",

"test-ci": "AJV_FULL_TEST=true npm test",
"prepublish": "npm run build"
"prepublish": "npm run build",
"benchmark": "npm i && npm run build && npm link && cd ./benchmark && npm link ajv && npm i && node ./jtd",
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},

@@ -79,2 +82,3 @@ "nyc": {

"@typescript-eslint/parser": "^3.8.0",
"@vuepress/shared-utils": "^1.8.2",
"ajv-formats": "^1.5.0",

@@ -101,3 +105,4 @@ "browserify": "^17.0.0",

"tsify": "^5.0.2",
"typescript": "^4.0.0"
"typescript": "^4.2.0",
"vuepress": "^1.8.2"
},

@@ -119,4 +124,4 @@ "collective": {

"lint-staged": {
"*.{md,json,yaml,js,ts}": "prettier --write"
"*.{json,yaml,js,ts}": "prettier --write"
}
}

@@ -1,9 +0,12 @@

<img align="right" alt="Ajv logo" width="160" src="https://ajv.js.org/images/ajv_logo.png">
<img align="right" alt="Ajv logo" width="160" src="https://ajv.js.org/img/ajv.svg">
&nbsp;
# Ajv: Another JSON schema validator
The fastest JSON schema validator for Node.js and browser.
Super fast JSON schema validator for Node.js and browser.
Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/).
::: v-pre
[![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild)

@@ -15,6 +18,7 @@ [![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv)

[![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin)
:::
## Platinum sponsors
[<img src="https://www.poberezkin.com/images/mozilla.svg" width="45%">](https://www.mozilla.org)[<img src="https://ajv.js.org/images/gap.svg" width="9%">](https://opencollective.com/ajv)[<img src="https://ajv.js.org/images/reserved.svg" width="45%">](https://opencollective.com/ajv)
[<img src="https://ajv.js.org/img/mozilla.svg" width="45%">](https://www.mozilla.org)<img src="https://ajv.js.org/img/gap.svg" width="5%">[<img src="https://ajv.js.org/img/reserved.svg" width="45%">](https://opencollective.com/ajv)

@@ -25,4 +29,4 @@ ## Using version 7

- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09).
- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0))
- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function.
- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/guide/combining-schemas.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09).
- to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements.

@@ -51,6 +55,22 @@ - to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%).

100+ people contributed to Ajv. You are very welcome to join by implementing new features that are valuable to many users and by improving documentation.
More than 100 people contributed to Ajv, and we would love to have you join the development. We welcome implementing new features that will benefit many users and ideas to improve our documentation.
Please do not be disappointed if your suggestion is not accepted - it is important to maintain the balance between the library size, performance and functionality. If it seems that a feature would benefit only a small number of users, its addition may be delayed until there is more support from the users community - so please submit the issue first to explain why this feature is important.
At Ajv, we are committed to creating more equitable and inclusive spaces for our community and team members to contribute to discussions that affect both this project and our ongoing work in the open source ecosystem.
We strive to create an environment of respect and healthy discourse by setting standards for our interactions and we expect it from all members of our community - from long term project member to first time visitor. For more information, review our [code of conduct](./CODE_OF_CONDUCT.md) and values.
### How we make decisions
We value conscious curation of our library size, and balancing performance and functionality. To that end, we cannot accept every suggestion. When evaluating pull requests we consider:
- Will this benefit many users or a niche use case?
- How will this impact the performance of Ajv?
- How will this expand our library size?
To help us evaluate and understand, when you submit an issue and pull request:
- Explain why this feature is important to the user base
- Include documentation
- Include test coverage with any new feature implementations
Please include documentation and test coverage with any new feature implementations.

@@ -68,3 +88,3 @@

Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md).
Please also review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md).

@@ -81,10 +101,8 @@ ## Contents

- [Getting started](#usage)
- [Choosing schema language](#choosing-schema-language)
- [JSON Schema](#json-schema)
- [JSON Type Definition](#json-type-definition)
- [Choosing schema language: JSON Schema vs JSON Type Definition](./docs/guide/schema-language.md#comparison)
- [Frequently Asked Questions](./docs/faq.md)
- [Using in browser](#using-in-browser)
- [Using in browser](./docs/guide/environments.md#browsers)
- [Content Security Policy](./docs/security.md#content-security-policy)
- [Using in ES5 environment](#using-in-es5-environment)
- [Command line interface](#command-line-interface)
- [Using in ES5 environment](./docs/guide/environments.md#es5-environments)
- [Command line interface](./docs/guide/environments.md#command-line-interface)
- [API reference](./docs/api.md)

@@ -99,12 +117,13 @@ - [Methods](./docs/api.md#ajv-constructor-and-methods)

- [Strict number validation](./docs/strict-mode.md#strict-number-validation)
- [Data validation](./docs/validation.md)
- [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats)
- [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/validation.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords)
- [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation)
- [Validation guide](./docs/guide/getting-started.md)
- [Getting started](./docs/guide/getting-started.md)
- [Validating formats](./docs/guide/formats.md)
- [Modular schemas](./docs/guide/combining-schemas.md): [combining with \$ref](./docs/guide/combining-schemas#ref), [\$data reference](./docs/guide/combining-schemas.md#data-reference), [$merge and $patch](./docs/guide/combining-schemas#merge-and-patch-keywords)
- [Asynchronous schema compilation](./docs/guide/managing-schemas.md#asynchronous-schema-compilation)
- [Standalone validation code](./docs/standalone.md)
- [Asynchronous validation](./docs/validation.md#asynchronous-validation)
- [Modifying data](./docs/validation.md#modifying-data-during-validation): [additional properties](./docs/validation.md#removing-additional-properties), [defaults](./docs/validation.md#assigning-defaults), [type coercion](./docs/validation.md#coercing-data-types)
- [Asynchronous validation](./docs/guide/async-validation.md)
- [Modifying data](./docs/guide/modifying-data.md): [additional properties](./docs/guide/modifying-data.md#removing-additional-properties), [defaults](./docs/guide/modifying-data.md#assigning-defaults), [type coercion](./docs/guide/modifying-data.md#coercing-data-types)
- [Extending Ajv](#extending-ajv)
- User-defined keywords:
- [basics](./docs/validation.md#user-defined-keywords)
- [basics](./docs/guide/user-keywords.md)
- [guide](./docs/keywords.md)

@@ -126,3 +145,5 @@ - [Plugins](#plugins)

[<img src="https://www.poberezkin.com/images/mozilla.png" width="240" height="68">](https://www.mozilla.org/en-US/moss/) &nbsp;&nbsp;&nbsp; [<img src="https://www.poberezkin.com/images/openjs.png" width="220" height="68">](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/)
::: v-pre
[<img src="https://ajv.js.org/img/mozilla.svg" width="240" height="68">](https://www.mozilla.org/en-US/moss/)<img src="https://ajv.js.org/img/gap.svg" width="5%">[<img src="https://ajv.js.org/img/openjs.png" width="220" height="68">](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/)
:::

@@ -195,9 +216,9 @@ Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/).

- supports [browsers](#using-in-browser) and Node.js 0.10-14.x
- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation
- [asynchronous loading](./docs/guide/managing-schemas.md#asynchronous-schema-compilation) of referenced schemas during compilation
- "All errors" validation mode with [option allErrors](./docs/api.md#options)
- [error messages with parameters](./docs/api.md#validation-errors) describing error reasons to allow error message generation
- i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package
- [removing-additional-properties](./docs/validation.md#removing-additional-properties)
- [assigning defaults](./docs/validation.md#assigning-defaults) to missing properties and items
- [coercing data](./docs/validation.md#coercing-data-types) to the types specified in `type` keywords
- [removing-additional-properties](./docs/guide/modifying-data.md#removing-additional-properties)
- [assigning defaults](./docs/guide/modifying-data.md#assigning-defaults) to missing properties and items
- [coercing data](./docs/guide/modifying-data.md#coercing-data-types) to the types specified in `type` keywords
- [user-defined keywords](#user-defined-keywords)

@@ -207,3 +228,3 @@ - draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else`

- additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package
- [\$data reference](./docs/validation.md#data-reference) to use values from the validated data as values for the schema keywords
- [\$data reference](./docs/guide/combining-schemas.md#data-reference) to use values from the validated data as values for the schema keywords
- [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords

@@ -237,206 +258,4 @@

In TypeScript:
See more examples in [Guide: getting started](./docs/guide/getting-started)
```typescript
import Ajv, {JSONSchemaType, DefinedError} from "ajv"
const ajv = new Ajv()
type MyData = {foo: number}
// Optional schema type annotation for schema to match MyData type.
// To use JSONSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`.
const schema: JSONSchemaType<MyData> = {
type: "object",
properties: {
foo: {type: "number", minimum: 0},
},
required: ["foo"],
additionalProperties: false,
}
// validate is a type guard for MyData - type is inferred from schema type
const validate = ajv.compile(schema)
// or, if you did not use type annotation for the schema,
// type parameter can be used to make it type guard:
// const validate = ajv.compile<MyData>(schema)
const data: any = {foo: 1}
if (validate(data)) {
// data is MyData here
console.log(data.foo)
} else {
// The type cast is needed to allow user-defined keywords and errors
// You can extend this type to include your error types as needed.
for (const err of validate.errors as DefinedError[]) {
switch (err.keyword) {
case "minimum":
// err type is narrowed here to have "minimum" error params properties
console.log(err.params.limit)
break
// ...
}
}
}
```
With JSON Type Definition schema:
```javascript
const Ajv = require("ajv").default
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
properties: {
foo: {type: "float64"},
},
}
const validate = ajv.compile(schema)
const valid = validate({foo: 1}) // true
if (!valid) console.log(validate.errors)
// Unlike JSON Schema:
const valid1 = validate(1) // false, bot an object
const valid2 = validate({}) // false, foo is required
const valid3 = validate({foo: 1, bar: 2}) // false, bar is additional
```
See [this test](./spec/types/json-schema.spec.ts) for an advanced example, [API reference](./docs/api.md) and [Options](./docs/api.md#options) for more details.
Ajv compiles schemas to functions and caches them in all cases (using schema itself as a key for Map) or another function passed via options), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again.
The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call).
**Please note**: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](./docs/api.md#validation-errors)
## Using in browser
See [Content Security Policy](./docs/security.md#content-security-policy) to decide the best approach how to use Ajv in the browser.
Whether you use Ajv or compiled schemas, it is recommended that you bundle them together with your code.
If you need to use Ajv in several bundles you can create a separate UMD bundles using `npm run bundle` script.
Then you need to load Ajv with support of JSON Schema draft-07 in the browser:
```html
<script src="bundle/ajv7.min.js"></script>
<script>
;(function () {
const Ajv = window.ajv7.default
const ajv = new Ajv()
})()
</script>
```
To load the bundle that supports JSON Schema draft-2019-09:
```html
<script src="bundle/ajv2019.min.js"></script>
<script>
;(function () {
const Ajv = window.ajv2019.default
const ajv = new Ajv()
})()
</script>
```
To load the bundle that supports JSON Type Definition:
```html
<script src="bundle/ajvJTD.min.js"></script>
<script>
;(function () {
const Ajv = window.ajvJTD.default
const ajv = new Ajv()
})()
</script>
```
This bundle can be used with different module systems; it creates global `ajv` (or `ajv2019`) if no module system is found.
The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv).
**Please note**: some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)).
## Choosing schema language
Both JSON Schema and JSON Type Definition are cross-platform specifications with implementations in multiple programming languages that help you define the shape and requirements to your JSON data.
This section compares their pros/cons to help decide which specification fits your application better.
### JSON Schema
- Pros
- Wide specification adoption.
- Used as part of OpenAPI specification.
- Support of complex validation scenarios:
- untagged unions and boolean logic
- conditional schemas and dependencies
- restrictions on the number ranges and the size of strings, arrays and objects
- semantic validation with formats, patterns and content keywords
- distribute strict record definitions across multiple schemas (with unevaluatedProperties)
- Can be effectively used for validation of any JavaScript objects and configuration files.
- Cons
- Defines the collection of restrictions on the data, rather than the shape of the data.
- No standard support for tagged unions.
- Complex and error prone for the new users (Ajv has [strict mode](./docs/strict-mode) to compensate for it, but it is not cross-platform).
- Some parts of specification are difficult to implement, creating the risk of implementations divergence:
- reference resolution model
- unevaluatedProperties/unevaluatedItems
- dynamic recursive references
- Internet draft status (rather than RFC)
See [JSON Schema](./docs/json-schema.md) for the list of defined keywords.
### JSON Type Definition
- Pros:
- Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types.
- Very simple, enforcing the best practices for cross-platform JSON API modelling.
- Simple to implement, ensuring consistency across implementations.
- Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions).
- Effective support for tagged unions.
- Designed to protect against user mistakes.
- Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/)
- Cons:
- Limited, compared with JSON Schema - no support for untagged unions<sup>\*</sup>, conditionals, references between different schema files<sup>\*\*</sup>, etc.
- No meta-schema in the specification<sup>\*</sup>.
- Brand new - limited industry adoption (as of January 2021).
<sup>\*</sup> Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object.
<sup>\*\*</sup> You can still combine schemas from multiple files in the application code.
See [JSON Type Definition](./docs/json-type-definition.md) for the list of defined schema forms.
## Using in ES5 environment
You need to:
- recompile Typescript to ES5 target - it is set to 2018 in the bundled compiled code.
- generate ES5 validation code:
```javascript
const ajv = new Ajv({code: {es5: true}})
```
See [Advanced options](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#advanced-options).
## Command line interface
CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). It supports:
- compiling JSON Schemas to test their validity
- generating [standalone validation code](./docs/standalone.md) that exports validation function(s) to be used without Ajv
- migrating schemas to draft-07 and draft-2019-09 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate))
- validating data file(s) against JSON Schema
- testing expected validity of data against JSON Schema
- referenced schemas
- user-defined meta-schemas, validation keywords and formats
- files in JSON, JSON5, YAML, and JavaScript format
- all Ajv options
- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format
## Extending Ajv

@@ -446,3 +265,3 @@

See section in [data validation](./docs/validation.md#user-defined-keywords) and the [detailed guide](./docs/keywords.md).
See section in [data validation](./docs/guide/user-keywords.md) and the [detailed guide](./docs/keywords.md).

@@ -500,3 +319,3 @@ ### Plugins

See https://github.com/ajv-validator/ajv/releases
See [https://github.com/ajv-validator/ajv/releases](https://github.com/ajv-validator/ajv/releases)

@@ -503,0 +322,0 @@ **Please note**: [Changes in version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc