Skip to content

Commit

Permalink
deprecated options [WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Sep 18, 2020
1 parent 5f5265f commit e61ffeb
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 27 deletions.
30 changes: 16 additions & 14 deletions README.md
Expand Up @@ -188,7 +188,7 @@ const schema: JSONSchemaType<MyData> = {
additionalProperties: false
}

// validate is a type guard for MyData because schema was typed
// 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,
Expand Down Expand Up @@ -992,14 +992,16 @@ See [Coercion rules](https://github.com/ajv-validator/ajv/blob/master/COERCION.m
## API
#### new Ajv(opts: object)
#### new Ajv(options: object)
Create Ajv instance:
```javascript
const ajv = new Ajv()
```
See [Options](#options)
#### ajv.compile(schema: object): (data: any) =\> boolean | Promise\<any\>
Generate validating function and cache the compiled schema for future use.
Expand Down Expand Up @@ -1194,7 +1196,7 @@ interface KeywordDefinition {
// (the latter can be used in addition to `compile` or `macro`).
$dataError?: object // error definition object for invalid \$data schema - see types.ts
async?: true // if the validation function is asynchronous
// (whether it is compiled or passed in `validate` property).
// (whether it is returned from `compile` or passed in `validate` property).
// It should return a promise that resolves with a value `true` or `false`.
// This option is ignored in case of "macro" and "code" keywords.
errors?: boolean | "full" // whether keyword returns errors.
Expand Down Expand Up @@ -1237,15 +1239,15 @@ const defaultOptions = {
// strict mode options
strict: true,
allowMatchingProperties: false,
validateFormats: true,
// validation and reporting options:
$data: false,
allErrors: false,
verbose: false,
$comment: false,
format: true,
formats: {},
keywords: {},
schemas: {},
$data: false // | true,
logger: undefined,
// referenced schema options:
missingRefs: true,
Expand Down Expand Up @@ -1274,13 +1276,16 @@ const defaultOptions = {
}
```
##### Strict mode options
##### Strict mode options (NEW in v7)
- _strict_ (NEW in v7): 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) 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:
- _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) 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.
- _allowMatchingProperties_ (NEW in v7): pass true to allow overlap between "properties" and "patternProperties". Does not affect other strict mode restrictions. See [Strict Mode](#strict-mode).
- _allowMatchingProperties_: pass true to allow overlap between "properties" and "patternProperties". Does not affect other strict mode restrictions. See [Strict Mode](#strict-mode).
- _validateFormats_: format validation. Option values:
- `true` (default) - validate formats (see [Formats](#formats)). In [strict mode](#strict-mode) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](#data-reference)).
- `false` - do not validate any format keywords (TODO they will still collect annotations once supported).
##### Validation and reporting options
Expand All @@ -1291,9 +1296,6 @@ const defaultOptions = {
- `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
- _format_: format validation. Option values:
- `true` (default) - validate added formats (see [Formats](#formats)). In strict mode unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](#data-reference)).
- `false` - ignore all format keywords.
- _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.
Expand Down Expand Up @@ -1338,9 +1340,9 @@ const defaultOptions = {
- `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 - that substantially improves performance at the cost of the bigger size of compiled schema functions.
- `false` - to not inline referenced schemas (they will be compiled as separate functions).
- integer number - to limit the maximum number of keywords of the schema that will be inlined.
- `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.
Expand Down
46 changes: 41 additions & 5 deletions lib/ajv.ts
Expand Up @@ -46,6 +46,7 @@ import type {
ErrorObject,
Format,
AddedFormat,
// DeprecatedOptions,
} from "./types"
import type {JSONSchemaType} from "./types/json-schema"
import Cache from "./cache"
Expand Down Expand Up @@ -90,6 +91,28 @@ const optsDefaults = {
addUsedSchema: true,
}

// enum Opt {
// Removed,
// Deprecated,
// }

// interface OptionInfo {
// st: Opt
// alt?: keyof Options
// msg?: string
// }

// const removedOptions: {[opt in keyof (RemovedOptions & DeprecatedOptions)]-?: OptionInfo} = {
// format: {st: Opt.Removed, alt: "validateFormats"},
// errorDataPath: {st: Opt.Removed, alt: "jsPropertySyntax"},
// nullable: {st: Opt.Removed, msg: '"nullable" keyword is supported by default'},
// schemaId: {st: Opt.Removed, msg: "draft-04 not supported in Ajv v7"},
// uniqueItems: {st: Opt.Removed},
// unknownFormats: {st: Opt.Removed, alt: "formats"},
// unicode: {st: Opt.Deprecated},
// jsPropertySyntax: {st: Opt.Deprecated},
// }

export default class Ajv {
opts: InstanceOptions
errors?: ErrorObject[] | null // errors from the last validation
Expand All @@ -115,14 +138,15 @@ export default class Ajv {
serialize: opts.serialize === false ? (x) => x : opts.serialize ?? stableStringify,
addUsedSchema: opts.addUsedSchema ?? true,
validateSchema: opts.validateSchema ?? true,
validateFormats: opts.validateFormats ?? true,
}
this.logger = getLogger(opts.logger)
const formatOpt = opts.format
opts.format = false
const formatOpt = opts.validateFormats
opts.validateFormats = false

this._cache = opts.cache || new Cache()
this.RULES = getRules()
checkDeprecatedOptions.call(this, opts)
checkRemovedOptions.call(this, opts)
this._metaOpts = getMetaSchemaOptions.call(this)

if (opts.formats) addInitialFormats.call(this)
Expand All @@ -137,7 +161,7 @@ export default class Ajv {
addDefaultMetaSchema.call(this)
if (typeof opts.meta == "object") this.addMetaSchema(opts.meta)
addInitialSchemas.call(this)
opts.format = formatOpt
opts.validateFormats = formatOpt
}

// Validate data using schema
Expand Down Expand Up @@ -520,11 +544,23 @@ export interface ErrorsTextOptions {
dataVar?: string
}

function checkDeprecatedOptions(this: Ajv, opts: Options & RemovedOptions): void {
function checkRemovedOptions(this: Ajv, opts: Options & RemovedOptions): void {
// for (const key in removedOptions) {
// const name = key as keyof RemovedOptions
// if (opts[name] === undefined) continue
// const msg = message(name)
// if (removedOptions[name].st === Opt.Removed) this.logger.error(msg)
// else this.logger.warn(msg)
// }

// function message(name: keyof RemovedOptions) {

// }
if (opts.errorDataPath !== undefined) this.logger.error("NOT SUPPORTED: option errorDataPath")
if (opts.schemaId !== undefined) this.logger.error("NOT SUPPORTED: option schemaId")
if (opts.uniqueItems !== undefined) this.logger.error("NOT SUPPORTED: option uniqueItems")
if (opts.unknownFormats !== undefined) this.logger.error("NOT SUPPORTED: option unknownFormats")
if (opts.format !== undefined) this.logger.error("NOT SUPPORTED: option formats")
if (opts.jsPropertySyntax !== undefined) this.logger.warn("DEPRECATED: option jsPropertySyntax")
if (opts.unicode !== undefined) this.logger.warn("DEPRECATED: option unicode")
}
Expand Down
18 changes: 12 additions & 6 deletions lib/types/index.ts
Expand Up @@ -35,12 +35,14 @@ export type LoadSchemaFunction = (
cb?: (err: Error | null, schema?: AnySchemaObject) => void
) => Promise<AnySchemaObject>

export interface Options {
export type Options = CurrentOptions & DeprecatedOptions

export interface CurrentOptions {
strict?: boolean | "log"
$data?: boolean
allErrors?: boolean
verbose?: boolean
format?: boolean
// format?: boolean
formats?: {[name: string]: Format}
keywords?: Vocabulary | {[x: string]: KeywordDefinition} // map is deprecated
schemas?: AnySchema[] | {[key: string]: AnySchema}
Expand Down Expand Up @@ -72,17 +74,20 @@ export interface Options {
| true
| ((comment: string, schemaPath?: string, rootSchema?: AnySchemaObject) => unknown)
allowMatchingProperties?: boolean // disables a strict mode restriction
// deprecated:
jsPropertySyntax?: boolean // added instead of jsonPointers
unicode?: boolean
validateFormats?: boolean
}

export interface CodeOptions {
formats?: Code // code to require (or construct) map of available formats - for standalone code
}

export interface DeprecatedOptions {
jsPropertySyntax?: boolean // added instead of jsonPointers
unicode?: boolean
}

export interface RemovedOptions {
// removed:
format?: boolean
errorDataPath?: "object" | "property"
nullable?: boolean // "nullable" keyword is supported by default
schemaId?: string
Expand All @@ -98,6 +103,7 @@ export interface InstanceOptions extends Options {
serialize: (schema: AnySchema) => unknown
addUsedSchema: boolean
validateSchema: boolean | "log"
validateFormats: boolean
}

export interface Logger {
Expand Down
2 changes: 1 addition & 1 deletion lib/vocabularies/format/format.ts
Expand Up @@ -34,7 +34,7 @@ const def: CodeKeywordDefinition = {
code(cxt: KeywordCxt, ruleType?: string) {
const {gen, data, $data, schema, schemaCode, it} = cxt
const {opts, errSchemaPath, schemaEnv, self} = it
if (opts.format === false) return
if (!opts.validateFormats) return

if ($data) validate$DataFormat()
else validateFormat()
Expand Down
2 changes: 1 addition & 1 deletion spec/options/options_validation.spec.ts
Expand Up @@ -6,7 +6,7 @@ describe("validation options", () => {
describe("format", () => {
it("should not validate formats if option format == false", () => {
const ajv = new _Ajv({formats: {date: DATE_FORMAT}}),
ajvFF = new _Ajv({formats: {date: DATE_FORMAT}, format: false})
ajvFF = new _Ajv({formats: {date: DATE_FORMAT}, validateFormats: false})

const schema = {format: "date"}
const invalideDateTime = "06/19/1963" // expects hyphens
Expand Down

0 comments on commit e61ffeb

Please sign in to comment.