Updated the files.

This commit is contained in:
Batuhan Berk Başoğlu 2024-02-08 19:38:41 -05:00
parent 1553e6b971
commit 753967d4f5
23418 changed files with 3784666 additions and 0 deletions

View file

@ -0,0 +1,56 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, not, Name} from "../../compile/codegen"
import {alwaysValidSchema, checkStrictMode, Type} from "../../compile/util"
export type AdditionalItemsError = ErrorObject<"additionalItems", {limit: number}, AnySchema>
const error: KeywordErrorDefinition = {
message: ({params: {len}}) => str`must NOT have more than ${len} items`,
params: ({params: {len}}) => _`{limit: ${len}}`,
}
const def: CodeKeywordDefinition = {
keyword: "additionalItems" as const,
type: "array",
schemaType: ["boolean", "object"],
before: "uniqueItems",
error,
code(cxt: KeywordCxt) {
const {parentSchema, it} = cxt
const {items} = parentSchema
if (!Array.isArray(items)) {
checkStrictMode(it, '"additionalItems" is ignored when "items" is not an array of schemas')
return
}
validateAdditionalItems(cxt, items)
},
}
export function validateAdditionalItems(cxt: KeywordCxt, items: AnySchema[]): void {
const {gen, schema, data, keyword, it} = cxt
it.items = true
const len = gen.const("len", _`${data}.length`)
if (schema === false) {
cxt.setParams({len: items.length})
cxt.pass(_`${len} <= ${items.length}`)
} else if (typeof schema == "object" && !alwaysValidSchema(it, schema)) {
const valid = gen.var("valid", _`${len} <= ${items.length}`) // TODO var
gen.if(not(valid), () => validateItems(valid))
cxt.ok(valid)
}
function validateItems(valid: Name): void {
gen.forRange("i", items.length, len, (i) => {
cxt.subschema({keyword, dataProp: i, dataPropType: Type.Num}, valid)
if (!it.allErrors) gen.if(not(valid), () => gen.break())
})
}
}
export default def

View file

@ -0,0 +1,118 @@
import type {
CodeKeywordDefinition,
AddedKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
AnySchema,
} from "../../types"
import {allSchemaProperties, usePattern, isOwnProperty} from "../code"
import {_, nil, or, not, Code, Name} from "../../compile/codegen"
import N from "../../compile/names"
import type {SubschemaArgs} from "../../compile/validate/subschema"
import {alwaysValidSchema, schemaRefOrVal, Type} from "../../compile/util"
export type AdditionalPropertiesError = ErrorObject<
"additionalProperties",
{additionalProperty: string},
AnySchema
>
const error: KeywordErrorDefinition = {
message: "must NOT have additional properties",
params: ({params}) => _`{additionalProperty: ${params.additionalProperty}}`,
}
const def: CodeKeywordDefinition & AddedKeywordDefinition = {
keyword: "additionalProperties",
type: ["object"],
schemaType: ["boolean", "object"],
allowUndefined: true,
trackErrors: true,
error,
code(cxt) {
const {gen, schema, parentSchema, data, errsCount, it} = cxt
/* istanbul ignore if */
if (!errsCount) throw new Error("ajv implementation error")
const {allErrors, opts} = it
it.props = true
if (opts.removeAdditional !== "all" && alwaysValidSchema(it, schema)) return
const props = allSchemaProperties(parentSchema.properties)
const patProps = allSchemaProperties(parentSchema.patternProperties)
checkAdditionalProperties()
cxt.ok(_`${errsCount} === ${N.errors}`)
function checkAdditionalProperties(): void {
gen.forIn("key", data, (key: Name) => {
if (!props.length && !patProps.length) additionalPropertyCode(key)
else gen.if(isAdditional(key), () => additionalPropertyCode(key))
})
}
function isAdditional(key: Name): Code {
let definedProp: Code
if (props.length > 8) {
// TODO maybe an option instead of hard-coded 8?
const propsSchema = schemaRefOrVal(it, parentSchema.properties, "properties")
definedProp = isOwnProperty(gen, propsSchema as Code, key)
} else if (props.length) {
definedProp = or(...props.map((p) => _`${key} === ${p}`))
} else {
definedProp = nil
}
if (patProps.length) {
definedProp = or(definedProp, ...patProps.map((p) => _`${usePattern(cxt, p)}.test(${key})`))
}
return not(definedProp)
}
function deleteAdditional(key: Name): void {
gen.code(_`delete ${data}[${key}]`)
}
function additionalPropertyCode(key: Name): void {
if (opts.removeAdditional === "all" || (opts.removeAdditional && schema === false)) {
deleteAdditional(key)
return
}
if (schema === false) {
cxt.setParams({additionalProperty: key})
cxt.error()
if (!allErrors) gen.break()
return
}
if (typeof schema == "object" && !alwaysValidSchema(it, schema)) {
const valid = gen.name("valid")
if (opts.removeAdditional === "failing") {
applyAdditionalSchema(key, valid, false)
gen.if(not(valid), () => {
cxt.reset()
deleteAdditional(key)
})
} else {
applyAdditionalSchema(key, valid)
if (!allErrors) gen.if(not(valid), () => gen.break())
}
}
}
function applyAdditionalSchema(key: Name, valid: Name, errors?: false): void {
const subschema: SubschemaArgs = {
keyword: "additionalProperties",
dataProp: key,
dataPropType: Type.Str,
}
if (errors === false) {
Object.assign(subschema, {
compositeRule: true,
createErrors: false,
allErrors: false,
})
}
cxt.subschema(subschema, valid)
}
},
}
export default def

22
my-app/node_modules/ajv/lib/vocabularies/applicator/allOf.ts generated vendored Executable file
View file

@ -0,0 +1,22 @@
import type {CodeKeywordDefinition, AnySchema} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {alwaysValidSchema} from "../../compile/util"
const def: CodeKeywordDefinition = {
keyword: "allOf",
schemaType: "array",
code(cxt: KeywordCxt) {
const {gen, schema, it} = cxt
/* istanbul ignore if */
if (!Array.isArray(schema)) throw new Error("ajv implementation error")
const valid = gen.name("valid")
schema.forEach((sch: AnySchema, i: number) => {
if (alwaysValidSchema(it, sch)) return
const schCxt = cxt.subschema({keyword: "allOf", schemaProp: i}, valid)
cxt.ok(valid)
cxt.mergeEvaluated(schCxt)
})
},
}
export default def

14
my-app/node_modules/ajv/lib/vocabularies/applicator/anyOf.ts generated vendored Executable file
View file

@ -0,0 +1,14 @@
import type {CodeKeywordDefinition, ErrorNoParams, AnySchema} from "../../types"
import {validateUnion} from "../code"
export type AnyOfError = ErrorNoParams<"anyOf", AnySchema[]>
const def: CodeKeywordDefinition = {
keyword: "anyOf",
schemaType: "array",
trackErrors: true,
code: validateUnion,
error: {message: "must match a schema in anyOf"},
}
export default def

View file

@ -0,0 +1,109 @@
import type {
CodeKeywordDefinition,
KeywordErrorDefinition,
ErrorObject,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, Name} from "../../compile/codegen"
import {alwaysValidSchema, checkStrictMode, Type} from "../../compile/util"
export type ContainsError = ErrorObject<
"contains",
{minContains: number; maxContains?: number},
AnySchema
>
const error: KeywordErrorDefinition = {
message: ({params: {min, max}}) =>
max === undefined
? str`must contain at least ${min} valid item(s)`
: str`must contain at least ${min} and no more than ${max} valid item(s)`,
params: ({params: {min, max}}) =>
max === undefined ? _`{minContains: ${min}}` : _`{minContains: ${min}, maxContains: ${max}}`,
}
const def: CodeKeywordDefinition = {
keyword: "contains",
type: "array",
schemaType: ["object", "boolean"],
before: "uniqueItems",
trackErrors: true,
error,
code(cxt: KeywordCxt) {
const {gen, schema, parentSchema, data, it} = cxt
let min: number
let max: number | undefined
const {minContains, maxContains} = parentSchema
if (it.opts.next) {
min = minContains === undefined ? 1 : minContains
max = maxContains
} else {
min = 1
}
const len = gen.const("len", _`${data}.length`)
cxt.setParams({min, max})
if (max === undefined && min === 0) {
checkStrictMode(it, `"minContains" == 0 without "maxContains": "contains" keyword ignored`)
return
}
if (max !== undefined && min > max) {
checkStrictMode(it, `"minContains" > "maxContains" is always invalid`)
cxt.fail()
return
}
if (alwaysValidSchema(it, schema)) {
let cond = _`${len} >= ${min}`
if (max !== undefined) cond = _`${cond} && ${len} <= ${max}`
cxt.pass(cond)
return
}
it.items = true
const valid = gen.name("valid")
if (max === undefined && min === 1) {
validateItems(valid, () => gen.if(valid, () => gen.break()))
} else if (min === 0) {
gen.let(valid, true)
if (max !== undefined) gen.if(_`${data}.length > 0`, validateItemsWithCount)
} else {
gen.let(valid, false)
validateItemsWithCount()
}
cxt.result(valid, () => cxt.reset())
function validateItemsWithCount(): void {
const schValid = gen.name("_valid")
const count = gen.let("count", 0)
validateItems(schValid, () => gen.if(schValid, () => checkLimits(count)))
}
function validateItems(_valid: Name, block: () => void): void {
gen.forRange("i", 0, len, (i) => {
cxt.subschema(
{
keyword: "contains",
dataProp: i,
dataPropType: Type.Num,
compositeRule: true,
},
_valid
)
block()
})
}
function checkLimits(count: Name): void {
gen.code(_`${count}++`)
if (max === undefined) {
gen.if(_`${count} >= ${min}`, () => gen.assign(valid, true).break())
} else {
gen.if(_`${count} > ${max}`, () => gen.assign(valid, false).break())
if (min === 1) gen.assign(valid, true)
else gen.if(_`${count} >= ${min}`, () => gen.assign(valid, true))
}
}
},
}
export default def

View file

@ -0,0 +1,112 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
SchemaMap,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str} from "../../compile/codegen"
import {alwaysValidSchema} from "../../compile/util"
import {checkReportMissingProp, checkMissingProp, reportMissingProp, propertyInData} from "../code"
export type PropertyDependencies = {[K in string]?: string[]}
export interface DependenciesErrorParams {
property: string
missingProperty: string
depsCount: number
deps: string // TODO change to string[]
}
type SchemaDependencies = SchemaMap
export type DependenciesError = ErrorObject<
"dependencies",
DependenciesErrorParams,
{[K in string]?: string[] | AnySchema}
>
export const error: KeywordErrorDefinition = {
message: ({params: {property, depsCount, deps}}) => {
const property_ies = depsCount === 1 ? "property" : "properties"
return str`must have ${property_ies} ${deps} when property ${property} is present`
},
params: ({params: {property, depsCount, deps, missingProperty}}) =>
_`{property: ${property},
missingProperty: ${missingProperty},
depsCount: ${depsCount},
deps: ${deps}}`, // TODO change to reference
}
const def: CodeKeywordDefinition = {
keyword: "dependencies",
type: "object",
schemaType: "object",
error,
code(cxt: KeywordCxt) {
const [propDeps, schDeps] = splitDependencies(cxt)
validatePropertyDeps(cxt, propDeps)
validateSchemaDeps(cxt, schDeps)
},
}
function splitDependencies({schema}: KeywordCxt): [PropertyDependencies, SchemaDependencies] {
const propertyDeps: PropertyDependencies = {}
const schemaDeps: SchemaDependencies = {}
for (const key in schema) {
if (key === "__proto__") continue
const deps = Array.isArray(schema[key]) ? propertyDeps : schemaDeps
deps[key] = schema[key]
}
return [propertyDeps, schemaDeps]
}
export function validatePropertyDeps(
cxt: KeywordCxt,
propertyDeps: {[K in string]?: string[]} = cxt.schema
): void {
const {gen, data, it} = cxt
if (Object.keys(propertyDeps).length === 0) return
const missing = gen.let("missing")
for (const prop in propertyDeps) {
const deps = propertyDeps[prop] as string[]
if (deps.length === 0) continue
const hasProperty = propertyInData(gen, data, prop, it.opts.ownProperties)
cxt.setParams({
property: prop,
depsCount: deps.length,
deps: deps.join(", "),
})
if (it.allErrors) {
gen.if(hasProperty, () => {
for (const depProp of deps) {
checkReportMissingProp(cxt, depProp)
}
})
} else {
gen.if(_`${hasProperty} && (${checkMissingProp(cxt, deps, missing)})`)
reportMissingProp(cxt, missing)
gen.else()
}
}
}
export function validateSchemaDeps(cxt: KeywordCxt, schemaDeps: SchemaMap = cxt.schema): void {
const {gen, data, keyword, it} = cxt
const valid = gen.name("valid")
for (const prop in schemaDeps) {
if (alwaysValidSchema(it, schemaDeps[prop] as AnySchema)) continue
gen.if(
propertyInData(gen, data, prop, it.opts.ownProperties),
() => {
const schCxt = cxt.subschema({keyword, schemaProp: prop}, valid)
cxt.mergeValidEvaluated(schCxt, valid)
},
() => gen.var(valid, true) // TODO var
)
cxt.ok(valid)
}
}
export default def

View file

@ -0,0 +1,11 @@
import type {CodeKeywordDefinition} from "../../types"
import {validateSchemaDeps} from "./dependencies"
const def: CodeKeywordDefinition = {
keyword: "dependentSchemas",
type: "object",
schemaType: "object",
code: (cxt) => validateSchemaDeps(cxt),
}
export default def

80
my-app/node_modules/ajv/lib/vocabularies/applicator/if.ts generated vendored Executable file
View file

@ -0,0 +1,80 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
AnySchema,
} from "../../types"
import type {SchemaObjCxt} from "../../compile"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, not, Name} from "../../compile/codegen"
import {alwaysValidSchema, checkStrictMode} from "../../compile/util"
export type IfKeywordError = ErrorObject<"if", {failingKeyword: string}, AnySchema>
const error: KeywordErrorDefinition = {
message: ({params}) => str`must match "${params.ifClause}" schema`,
params: ({params}) => _`{failingKeyword: ${params.ifClause}}`,
}
const def: CodeKeywordDefinition = {
keyword: "if",
schemaType: ["object", "boolean"],
trackErrors: true,
error,
code(cxt: KeywordCxt) {
const {gen, parentSchema, it} = cxt
if (parentSchema.then === undefined && parentSchema.else === undefined) {
checkStrictMode(it, '"if" without "then" and "else" is ignored')
}
const hasThen = hasSchema(it, "then")
const hasElse = hasSchema(it, "else")
if (!hasThen && !hasElse) return
const valid = gen.let("valid", true)
const schValid = gen.name("_valid")
validateIf()
cxt.reset()
if (hasThen && hasElse) {
const ifClause = gen.let("ifClause")
cxt.setParams({ifClause})
gen.if(schValid, validateClause("then", ifClause), validateClause("else", ifClause))
} else if (hasThen) {
gen.if(schValid, validateClause("then"))
} else {
gen.if(not(schValid), validateClause("else"))
}
cxt.pass(valid, () => cxt.error(true))
function validateIf(): void {
const schCxt = cxt.subschema(
{
keyword: "if",
compositeRule: true,
createErrors: false,
allErrors: false,
},
schValid
)
cxt.mergeEvaluated(schCxt)
}
function validateClause(keyword: string, ifClause?: Name): () => void {
return () => {
const schCxt = cxt.subschema({keyword}, schValid)
gen.assign(valid, schValid)
cxt.mergeValidEvaluated(schCxt, valid)
if (ifClause) gen.assign(ifClause, _`${keyword}`)
else cxt.setParams({ifClause: keyword})
}
}
},
}
function hasSchema(it: SchemaObjCxt, keyword: string): boolean {
const schema = it.schema[keyword]
return schema !== undefined && !alwaysValidSchema(it, schema)
}
export default def

53
my-app/node_modules/ajv/lib/vocabularies/applicator/index.ts generated vendored Executable file
View file

@ -0,0 +1,53 @@
import type {ErrorNoParams, Vocabulary} from "../../types"
import additionalItems, {AdditionalItemsError} from "./additionalItems"
import prefixItems from "./prefixItems"
import items from "./items"
import items2020, {ItemsError} from "./items2020"
import contains, {ContainsError} from "./contains"
import dependencies, {DependenciesError} from "./dependencies"
import propertyNames, {PropertyNamesError} from "./propertyNames"
import additionalProperties, {AdditionalPropertiesError} from "./additionalProperties"
import properties from "./properties"
import patternProperties from "./patternProperties"
import notKeyword, {NotKeywordError} from "./not"
import anyOf, {AnyOfError} from "./anyOf"
import oneOf, {OneOfError} from "./oneOf"
import allOf from "./allOf"
import ifKeyword, {IfKeywordError} from "./if"
import thenElse from "./thenElse"
export default function getApplicator(draft2020 = false): Vocabulary {
const applicator = [
// any
notKeyword,
anyOf,
oneOf,
allOf,
ifKeyword,
thenElse,
// object
propertyNames,
additionalProperties,
dependencies,
properties,
patternProperties,
]
// array
if (draft2020) applicator.push(prefixItems, items2020)
else applicator.push(additionalItems, items)
applicator.push(contains)
return applicator
}
export type ApplicatorKeywordError =
| ErrorNoParams<"false schema">
| AdditionalItemsError
| ItemsError
| ContainsError
| AdditionalPropertiesError
| DependenciesError
| IfKeywordError
| AnyOfError
| OneOfError
| NotKeywordError
| PropertyNamesError

59
my-app/node_modules/ajv/lib/vocabularies/applicator/items.ts generated vendored Executable file
View file

@ -0,0 +1,59 @@
import type {CodeKeywordDefinition, AnySchema, AnySchemaObject} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_} from "../../compile/codegen"
import {alwaysValidSchema, mergeEvaluated, checkStrictMode} from "../../compile/util"
import {validateArray} from "../code"
const def: CodeKeywordDefinition = {
keyword: "items",
type: "array",
schemaType: ["object", "array", "boolean"],
before: "uniqueItems",
code(cxt: KeywordCxt) {
const {schema, it} = cxt
if (Array.isArray(schema)) return validateTuple(cxt, "additionalItems", schema)
it.items = true
if (alwaysValidSchema(it, schema)) return
cxt.ok(validateArray(cxt))
},
}
export function validateTuple(
cxt: KeywordCxt,
extraItems: string,
schArr: AnySchema[] = cxt.schema
): void {
const {gen, parentSchema, data, keyword, it} = cxt
checkStrictTuple(parentSchema)
if (it.opts.unevaluated && schArr.length && it.items !== true) {
it.items = mergeEvaluated.items(gen, schArr.length, it.items)
}
const valid = gen.name("valid")
const len = gen.const("len", _`${data}.length`)
schArr.forEach((sch: AnySchema, i: number) => {
if (alwaysValidSchema(it, sch)) return
gen.if(_`${len} > ${i}`, () =>
cxt.subschema(
{
keyword,
schemaProp: i,
dataProp: i,
},
valid
)
)
cxt.ok(valid)
})
function checkStrictTuple(sch: AnySchemaObject): void {
const {opts, errSchemaPath} = it
const l = schArr.length
const fullTuple = l === sch.minItems && (l === sch.maxItems || sch[extraItems] === false)
if (opts.strictTuples && !fullTuple) {
const msg = `"${keyword}" is ${l}-tuple, but minItems or maxItems/${extraItems} are not specified or different at path "${errSchemaPath}"`
checkStrictMode(it, msg, opts.strictTuples)
}
}
}
export default def

View file

@ -0,0 +1,36 @@
import type {
CodeKeywordDefinition,
KeywordErrorDefinition,
ErrorObject,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str} from "../../compile/codegen"
import {alwaysValidSchema} from "../../compile/util"
import {validateArray} from "../code"
import {validateAdditionalItems} from "./additionalItems"
export type ItemsError = ErrorObject<"items", {limit: number}, AnySchema>
const error: KeywordErrorDefinition = {
message: ({params: {len}}) => str`must NOT have more than ${len} items`,
params: ({params: {len}}) => _`{limit: ${len}}`,
}
const def: CodeKeywordDefinition = {
keyword: "items",
type: "array",
schemaType: ["object", "boolean"],
before: "uniqueItems",
error,
code(cxt: KeywordCxt) {
const {schema, parentSchema, it} = cxt
const {prefixItems} = parentSchema
it.items = true
if (alwaysValidSchema(it, schema)) return
if (prefixItems) validateAdditionalItems(cxt, prefixItems)
else cxt.ok(validateArray(cxt))
},
}
export default def

38
my-app/node_modules/ajv/lib/vocabularies/applicator/not.ts generated vendored Executable file
View file

@ -0,0 +1,38 @@
import type {CodeKeywordDefinition, ErrorNoParams, AnySchema} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {alwaysValidSchema} from "../../compile/util"
export type NotKeywordError = ErrorNoParams<"not", AnySchema>
const def: CodeKeywordDefinition = {
keyword: "not",
schemaType: ["object", "boolean"],
trackErrors: true,
code(cxt: KeywordCxt) {
const {gen, schema, it} = cxt
if (alwaysValidSchema(it, schema)) {
cxt.fail()
return
}
const valid = gen.name("valid")
cxt.subschema(
{
keyword: "not",
compositeRule: true,
createErrors: false,
allErrors: false,
},
valid
)
cxt.failResult(
valid,
() => cxt.reset(),
() => cxt.error()
)
},
error: {message: "must NOT be valid"},
}
export default def

82
my-app/node_modules/ajv/lib/vocabularies/applicator/oneOf.ts generated vendored Executable file
View file

@ -0,0 +1,82 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, Name} from "../../compile/codegen"
import {alwaysValidSchema} from "../../compile/util"
import {SchemaCxt} from "../../compile"
export type OneOfError = ErrorObject<
"oneOf",
{passingSchemas: [number, number] | null},
AnySchema[]
>
const error: KeywordErrorDefinition = {
message: "must match exactly one schema in oneOf",
params: ({params}) => _`{passingSchemas: ${params.passing}}`,
}
const def: CodeKeywordDefinition = {
keyword: "oneOf",
schemaType: "array",
trackErrors: true,
error,
code(cxt: KeywordCxt) {
const {gen, schema, parentSchema, it} = cxt
/* istanbul ignore if */
if (!Array.isArray(schema)) throw new Error("ajv implementation error")
if (it.opts.discriminator && parentSchema.discriminator) return
const schArr: AnySchema[] = schema
const valid = gen.let("valid", false)
const passing = gen.let("passing", null)
const schValid = gen.name("_valid")
cxt.setParams({passing})
// TODO possibly fail straight away (with warning or exception) if there are two empty always valid schemas
gen.block(validateOneOf)
cxt.result(
valid,
() => cxt.reset(),
() => cxt.error(true)
)
function validateOneOf(): void {
schArr.forEach((sch: AnySchema, i: number) => {
let schCxt: SchemaCxt | undefined
if (alwaysValidSchema(it, sch)) {
gen.var(schValid, true)
} else {
schCxt = cxt.subschema(
{
keyword: "oneOf",
schemaProp: i,
compositeRule: true,
},
schValid
)
}
if (i > 0) {
gen
.if(_`${schValid} && ${valid}`)
.assign(valid, false)
.assign(passing, _`[${passing}, ${i}]`)
.else()
}
gen.if(schValid, () => {
gen.assign(valid, true)
gen.assign(passing, i)
if (schCxt) cxt.mergeEvaluated(schCxt, Name)
})
})
}
},
}
export default def

View file

@ -0,0 +1,91 @@
import type {CodeKeywordDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {allSchemaProperties, usePattern} from "../code"
import {_, not, Name} from "../../compile/codegen"
import {alwaysValidSchema, checkStrictMode} from "../../compile/util"
import {evaluatedPropsToName, Type} from "../../compile/util"
import {AnySchema} from "../../types"
const def: CodeKeywordDefinition = {
keyword: "patternProperties",
type: "object",
schemaType: "object",
code(cxt: KeywordCxt) {
const {gen, schema, data, parentSchema, it} = cxt
const {opts} = it
const patterns = allSchemaProperties(schema)
const alwaysValidPatterns = patterns.filter((p) =>
alwaysValidSchema(it, schema[p] as AnySchema)
)
if (
patterns.length === 0 ||
(alwaysValidPatterns.length === patterns.length &&
(!it.opts.unevaluated || it.props === true))
) {
return
}
const checkProperties =
opts.strictSchema && !opts.allowMatchingProperties && parentSchema.properties
const valid = gen.name("valid")
if (it.props !== true && !(it.props instanceof Name)) {
it.props = evaluatedPropsToName(gen, it.props)
}
const {props} = it
validatePatternProperties()
function validatePatternProperties(): void {
for (const pat of patterns) {
if (checkProperties) checkMatchingProperties(pat)
if (it.allErrors) {
validateProperties(pat)
} else {
gen.var(valid, true) // TODO var
validateProperties(pat)
gen.if(valid)
}
}
}
function checkMatchingProperties(pat: string): void {
for (const prop in checkProperties) {
if (new RegExp(pat).test(prop)) {
checkStrictMode(
it,
`property ${prop} matches pattern ${pat} (use allowMatchingProperties)`
)
}
}
}
function validateProperties(pat: string): void {
gen.forIn("key", data, (key) => {
gen.if(_`${usePattern(cxt, pat)}.test(${key})`, () => {
const alwaysValid = alwaysValidPatterns.includes(pat)
if (!alwaysValid) {
cxt.subschema(
{
keyword: "patternProperties",
schemaProp: pat,
dataProp: key,
dataPropType: Type.Str,
},
valid
)
}
if (it.opts.unevaluated && props !== true) {
gen.assign(_`${props}[${key}]`, true)
} else if (!alwaysValid && !it.allErrors) {
// can short-circuit if `unevaluatedProperties` is not supported (opts.next === false)
// or if all properties were evaluated (props === true)
gen.if(not(valid), () => gen.break())
}
})
})
}
},
}
export default def

View file

@ -0,0 +1,12 @@
import type {CodeKeywordDefinition} from "../../types"
import {validateTuple} from "./items"
const def: CodeKeywordDefinition = {
keyword: "prefixItems",
type: "array",
schemaType: ["array"],
before: "uniqueItems",
code: (cxt) => validateTuple(cxt, "items"),
}
export default def

View file

@ -0,0 +1,57 @@
import type {CodeKeywordDefinition} from "../../types"
import {KeywordCxt} from "../../compile/validate"
import {propertyInData, allSchemaProperties} from "../code"
import {alwaysValidSchema, toHash, mergeEvaluated} from "../../compile/util"
import apDef from "./additionalProperties"
const def: CodeKeywordDefinition = {
keyword: "properties",
type: "object",
schemaType: "object",
code(cxt: KeywordCxt) {
const {gen, schema, parentSchema, data, it} = cxt
if (it.opts.removeAdditional === "all" && parentSchema.additionalProperties === undefined) {
apDef.code(new KeywordCxt(it, apDef, "additionalProperties"))
}
const allProps = allSchemaProperties(schema)
for (const prop of allProps) {
it.definedProperties.add(prop)
}
if (it.opts.unevaluated && allProps.length && it.props !== true) {
it.props = mergeEvaluated.props(gen, toHash(allProps), it.props)
}
const properties = allProps.filter((p) => !alwaysValidSchema(it, schema[p]))
if (properties.length === 0) return
const valid = gen.name("valid")
for (const prop of properties) {
if (hasDefault(prop)) {
applyPropertySchema(prop)
} else {
gen.if(propertyInData(gen, data, prop, it.opts.ownProperties))
applyPropertySchema(prop)
if (!it.allErrors) gen.else().var(valid, true)
gen.endIf()
}
cxt.it.definedProperties.add(prop)
cxt.ok(valid)
}
function hasDefault(prop: string): boolean | undefined {
return it.opts.useDefaults && !it.compositeRule && schema[prop].default !== undefined
}
function applyPropertySchema(prop: string): void {
cxt.subschema(
{
keyword: "properties",
schemaProp: prop,
dataProp: prop,
},
valid
)
}
},
}
export default def

View file

@ -0,0 +1,50 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, not} from "../../compile/codegen"
import {alwaysValidSchema} from "../../compile/util"
export type PropertyNamesError = ErrorObject<"propertyNames", {propertyName: string}, AnySchema>
const error: KeywordErrorDefinition = {
message: "property name must be valid",
params: ({params}) => _`{propertyName: ${params.propertyName}}`,
}
const def: CodeKeywordDefinition = {
keyword: "propertyNames",
type: "object",
schemaType: ["object", "boolean"],
error,
code(cxt: KeywordCxt) {
const {gen, schema, data, it} = cxt
if (alwaysValidSchema(it, schema)) return
const valid = gen.name("valid")
gen.forIn("key", data, (key) => {
cxt.setParams({propertyName: key})
cxt.subschema(
{
keyword: "propertyNames",
data: key,
dataTypes: ["string"],
propertyName: key,
compositeRule: true,
},
valid
)
gen.if(not(valid), () => {
cxt.error(true)
if (!it.allErrors) gen.break()
})
})
cxt.ok(valid)
},
}
export default def

View file

@ -0,0 +1,13 @@
import type {CodeKeywordDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {checkStrictMode} from "../../compile/util"
const def: CodeKeywordDefinition = {
keyword: ["then", "else"],
schemaType: ["object", "boolean"],
code({keyword, parentSchema, it}: KeywordCxt) {
if (parentSchema.if === undefined) checkStrictMode(it, `"${keyword}" without "if" is ignored`)
},
}
export default def

168
my-app/node_modules/ajv/lib/vocabularies/code.ts generated vendored Executable file
View file

@ -0,0 +1,168 @@
import type {AnySchema, SchemaMap} from "../types"
import type {SchemaCxt} from "../compile"
import type {KeywordCxt} from "../compile/validate"
import {CodeGen, _, and, or, not, nil, strConcat, getProperty, Code, Name} from "../compile/codegen"
import {alwaysValidSchema, Type} from "../compile/util"
import N from "../compile/names"
import {useFunc} from "../compile/util"
export function checkReportMissingProp(cxt: KeywordCxt, prop: string): void {
const {gen, data, it} = cxt
gen.if(noPropertyInData(gen, data, prop, it.opts.ownProperties), () => {
cxt.setParams({missingProperty: _`${prop}`}, true)
cxt.error()
})
}
export function checkMissingProp(
{gen, data, it: {opts}}: KeywordCxt,
properties: string[],
missing: Name
): Code {
return or(
...properties.map((prop) =>
and(noPropertyInData(gen, data, prop, opts.ownProperties), _`${missing} = ${prop}`)
)
)
}
export function reportMissingProp(cxt: KeywordCxt, missing: Name): void {
cxt.setParams({missingProperty: missing}, true)
cxt.error()
}
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 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(gen, data, property)}` : cond
}
export function noPropertyInData(
gen: CodeGen,
data: Name,
property: Name | string,
ownProperties?: boolean
): Code {
const cond = _`${data}${getProperty(property)} === undefined`
return ownProperties ? or(cond, not(isOwnProperty(gen, data, property))) : cond
}
export function allSchemaProperties(schemaMap?: SchemaMap): string[] {
return schemaMap ? Object.keys(schemaMap).filter((p) => p !== "__proto__") : []
}
export function schemaProperties(it: SchemaCxt, schemaMap: SchemaMap): string[] {
return allSchemaProperties(schemaMap).filter(
(p) => !alwaysValidSchema(it, schemaMap[p] as AnySchema)
)
}
export function callValidateCode(
{schemaCode, data, it: {gen, topSchemaRef, schemaPath, errorPath}, it}: KeywordCxt,
func: Code,
context: Code,
passSchema?: boolean
): Code {
const dataAndSchema = passSchema ? _`${schemaCode}, ${data}, ${topSchemaRef}${schemaPath}` : data
const valCxt: [Name, Code | number][] = [
[N.instancePath, strConcat(N.instancePath, errorPath)],
[N.parentData, it.parentData],
[N.parentDataProperty, it.parentDataProperty],
[N.rootData, N.rootData],
]
if (it.opts.dynamicRef) valCxt.push([N.dynamicAnchors, N.dynamicAnchors])
const args = _`${dataAndSchema}, ${gen.object(...valCxt)}`
return context !== nil ? _`${func}.call(${context}, ${args})` : _`${func}(${args})`
}
const newRegExp = _`new RegExp`
export function usePattern({gen, it: {opts}}: KeywordCxt, pattern: string): Name {
const u = opts.unicodeRegExp ? "u" : ""
const {regExp} = opts.code
const rx = regExp(pattern, u)
return gen.scopeValue("pattern", {
key: rx.toString(),
ref: rx,
code: _`${regExp.code === "new RegExp" ? newRegExp : useFunc(gen, regExp)}(${pattern}, ${u})`,
})
}
export function validateArray(cxt: KeywordCxt): Name {
const {gen, data, keyword, it} = cxt
const valid = gen.name("valid")
if (it.allErrors) {
const validArr = gen.let("valid", true)
validateItems(() => gen.assign(validArr, false))
return validArr
}
gen.var(valid, true)
validateItems(() => gen.break())
return valid
function validateItems(notValid: () => void): void {
const len = gen.const("len", _`${data}.length`)
gen.forRange("i", 0, len, (i) => {
cxt.subschema(
{
keyword,
dataProp: i,
dataPropType: Type.Num,
},
valid
)
gen.if(not(valid), notValid)
})
}
}
export function validateUnion(cxt: KeywordCxt): void {
const {gen, schema, keyword, it} = cxt
/* istanbul ignore if */
if (!Array.isArray(schema)) throw new Error("ajv implementation error")
const alwaysValid = schema.some((sch: AnySchema) => alwaysValidSchema(it, sch))
if (alwaysValid && !it.opts.unevaluated) return
const valid = gen.let("valid", false)
const schValid = gen.name("_valid")
gen.block(() =>
schema.forEach((_sch: AnySchema, i: number) => {
const schCxt = cxt.subschema(
{
keyword,
schemaProp: i,
compositeRule: true,
},
schValid
)
gen.assign(valid, _`${valid} || ${schValid}`)
const merged = cxt.mergeValidEvaluated(schCxt, schValid)
// can short-circuit if `unevaluatedProperties/Items` not supported (opts.unevaluated !== true)
// or if all properties and items were evaluated (it.props === true && it.items === true)
if (!merged) gen.if(not(valid))
})
)
cxt.result(
valid,
() => cxt.reset(),
() => cxt.error(true)
)
}

10
my-app/node_modules/ajv/lib/vocabularies/core/id.ts generated vendored Executable file
View file

@ -0,0 +1,10 @@
import type {CodeKeywordDefinition} from "../../types"
const def: CodeKeywordDefinition = {
keyword: "id",
code() {
throw new Error('NOT SUPPORTED: keyword "id", use "$id" for schema ID')
},
}
export default def

16
my-app/node_modules/ajv/lib/vocabularies/core/index.ts generated vendored Executable file
View file

@ -0,0 +1,16 @@
import type {Vocabulary} from "../../types"
import idKeyword from "./id"
import refKeyword from "./ref"
const core: Vocabulary = [
"$schema",
"$id",
"$defs",
"$vocabulary",
{keyword: "$comment"},
"definitions",
idKeyword,
refKeyword,
]
export default core

129
my-app/node_modules/ajv/lib/vocabularies/core/ref.ts generated vendored Executable file
View file

@ -0,0 +1,129 @@
import type {CodeKeywordDefinition, AnySchema} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import MissingRefError from "../../compile/ref_error"
import {callValidateCode} from "../code"
import {_, nil, stringify, Code, Name} from "../../compile/codegen"
import N from "../../compile/names"
import {SchemaEnv, resolveRef} from "../../compile"
import {mergeEvaluated} from "../../compile/util"
const def: CodeKeywordDefinition = {
keyword: "$ref",
schemaType: "string",
code(cxt: KeywordCxt): void {
const {gen, schema: $ref, it} = cxt
const {baseId, schemaEnv: env, validateName, opts, self} = it
const {root} = env
if (($ref === "#" || $ref === "#/") && baseId === root.baseId) return callRootRef()
const schOrEnv = resolveRef.call(self, root, baseId, $ref)
if (schOrEnv === undefined) throw new MissingRefError(it.opts.uriResolver, baseId, $ref)
if (schOrEnv instanceof SchemaEnv) return callValidate(schOrEnv)
return inlineRefSchema(schOrEnv)
function callRootRef(): void {
if (env === root) return callRef(cxt, validateName, env, env.$async)
const rootName = gen.scopeValue("root", {ref: root})
return callRef(cxt, _`${rootName}.validate`, root, root.$async)
}
function callValidate(sch: SchemaEnv): void {
const v = getValidate(cxt, sch)
callRef(cxt, v, sch, sch.$async)
}
function inlineRefSchema(sch: AnySchema): void {
const schName = gen.scopeValue(
"schema",
opts.code.source === true ? {ref: sch, code: stringify(sch)} : {ref: sch}
)
const valid = gen.name("valid")
const schCxt = cxt.subschema(
{
schema: sch,
dataTypes: [],
schemaPath: nil,
topSchemaRef: schName,
errSchemaPath: $ref,
},
valid
)
cxt.mergeEvaluated(schCxt)
cxt.ok(valid)
}
},
}
export function getValidate(cxt: KeywordCxt, sch: SchemaEnv): Code {
const {gen} = cxt
return sch.validate
? gen.scopeValue("validate", {ref: sch.validate})
: _`${gen.scopeValue("wrapper", {ref: sch})}.validate`
}
export function callRef(cxt: KeywordCxt, v: Code, sch?: SchemaEnv, $async?: boolean): void {
const {gen, it} = cxt
const {allErrors, schemaEnv: env, opts} = it
const passCxt = opts.passContext ? N.this : nil
if ($async) callAsyncRef()
else callSyncRef()
function callAsyncRef(): void {
if (!env.$async) throw new Error("async schema referenced by sync schema")
const valid = gen.let("valid")
gen.try(
() => {
gen.code(_`await ${callValidateCode(cxt, v, passCxt)}`)
addEvaluatedFrom(v) // TODO will not work with async, it has to be returned with the result
if (!allErrors) gen.assign(valid, true)
},
(e) => {
gen.if(_`!(${e} instanceof ${it.ValidationError as Name})`, () => gen.throw(e))
addErrorsFrom(e)
if (!allErrors) gen.assign(valid, false)
}
)
cxt.ok(valid)
}
function callSyncRef(): void {
cxt.result(
callValidateCode(cxt, v, passCxt),
() => addEvaluatedFrom(v),
() => addErrorsFrom(v)
)
}
function addErrorsFrom(source: Code): void {
const errs = _`${source}.errors`
gen.assign(N.vErrors, _`${N.vErrors} === null ? ${errs} : ${N.vErrors}.concat(${errs})`) // TODO tagged
gen.assign(N.errors, _`${N.vErrors}.length`)
}
function addEvaluatedFrom(source: Code): void {
if (!it.opts.unevaluated) return
const schEvaluated = sch?.validate?.evaluated
// TODO refactor
if (it.props !== true) {
if (schEvaluated && !schEvaluated.dynamicProps) {
if (schEvaluated.props !== undefined) {
it.props = mergeEvaluated.props(gen, schEvaluated.props, it.props)
}
} else {
const props = gen.var("props", _`${source}.evaluated.props`)
it.props = mergeEvaluated.props(gen, props, it.props, Name)
}
}
if (it.items !== true) {
if (schEvaluated && !schEvaluated.dynamicItems) {
if (schEvaluated.items !== undefined) {
it.items = mergeEvaluated.items(gen, schEvaluated.items, it.items)
}
} else {
const items = gen.var("items", _`${source}.evaluated.items`)
it.items = mergeEvaluated.items(gen, items, it.items, Name)
}
}
}
}
export default def

View file

@ -0,0 +1,110 @@
import type {CodeKeywordDefinition, AnySchemaObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, getProperty, Name} from "../../compile/codegen"
import {DiscrError, DiscrErrorObj} from "../discriminator/types"
import {resolveRef, SchemaEnv} from "../../compile"
import {schemaHasRulesButRef} from "../../compile/util"
export type DiscriminatorError = DiscrErrorObj<DiscrError.Tag> | DiscrErrorObj<DiscrError.Mapping>
const error: KeywordErrorDefinition = {
message: ({params: {discrError, tagName}}) =>
discrError === DiscrError.Tag
? `tag "${tagName}" must be string`
: `value of tag "${tagName}" must be in oneOf`,
params: ({params: {discrError, tag, tagName}}) =>
_`{error: ${discrError}, tag: ${tagName}, tagValue: ${tag}}`,
}
const def: CodeKeywordDefinition = {
keyword: "discriminator",
type: "object",
schemaType: "object",
error,
code(cxt: KeywordCxt) {
const {gen, data, schema, parentSchema, it} = cxt
const {oneOf} = parentSchema
if (!it.opts.discriminator) {
throw new Error("discriminator: requires discriminator option")
}
const tagName = schema.propertyName
if (typeof tagName != "string") throw new Error("discriminator: requires propertyName")
if (schema.mapping) throw new Error("discriminator: mapping is not supported")
if (!oneOf) throw new Error("discriminator: requires oneOf keyword")
const valid = gen.let("valid", false)
const tag = gen.const("tag", _`${data}${getProperty(tagName)}`)
gen.if(
_`typeof ${tag} == "string"`,
() => validateMapping(),
() => cxt.error(false, {discrError: DiscrError.Tag, tag, tagName})
)
cxt.ok(valid)
function validateMapping(): void {
const mapping = getMapping()
gen.if(false)
for (const tagValue in mapping) {
gen.elseIf(_`${tag} === ${tagValue}`)
gen.assign(valid, applyTagSchema(mapping[tagValue]))
}
gen.else()
cxt.error(false, {discrError: DiscrError.Mapping, tag, tagName})
gen.endIf()
}
function applyTagSchema(schemaProp?: number): Name {
const _valid = gen.name("valid")
const schCxt = cxt.subschema({keyword: "oneOf", schemaProp}, _valid)
cxt.mergeEvaluated(schCxt, Name)
return _valid
}
function getMapping(): {[T in string]?: number} {
const oneOfMapping: {[T in string]?: number} = {}
const topRequired = hasRequired(parentSchema)
let tagRequired = true
for (let i = 0; i < oneOf.length; i++) {
let sch = oneOf[i]
if (sch?.$ref && !schemaHasRulesButRef(sch, it.self.RULES)) {
sch = resolveRef.call(it.self, it.schemaEnv.root, it.baseId, sch?.$ref)
if (sch instanceof SchemaEnv) sch = sch.schema
}
const propSch = sch?.properties?.[tagName]
if (typeof propSch != "object") {
throw new Error(
`discriminator: oneOf subschemas (or referenced schemas) must have "properties/${tagName}"`
)
}
tagRequired = tagRequired && (topRequired || hasRequired(sch))
addMappings(propSch, i)
}
if (!tagRequired) throw new Error(`discriminator: "${tagName}" must be required`)
return oneOfMapping
function hasRequired({required}: AnySchemaObject): boolean {
return Array.isArray(required) && required.includes(tagName)
}
function addMappings(sch: AnySchemaObject, i: number): void {
if (sch.const) {
addMapping(sch.const, i)
} else if (sch.enum) {
for (const tagValue of sch.enum) {
addMapping(tagValue, i)
}
} else {
throw new Error(`discriminator: "properties/${tagName}" must have "const" or "enum"`)
}
}
function addMapping(tagValue: unknown, i: number): void {
if (typeof tagValue != "string" || tagValue in oneOfMapping) {
throw new Error(`discriminator: "${tagName}" values must be unique strings`)
}
oneOfMapping[tagValue] = i
}
}
},
}
export default def

View file

@ -0,0 +1,12 @@
import type {ErrorObject} from "../../types"
export enum DiscrError {
Tag = "tag",
Mapping = "mapping",
}
export type DiscrErrorObj<E extends DiscrError> = ErrorObject<
"discriminator",
{error: E; tag: string; tagValue: unknown},
string
>

23
my-app/node_modules/ajv/lib/vocabularies/draft2020.ts generated vendored Executable file
View file

@ -0,0 +1,23 @@
import type {Vocabulary} from "../types"
import coreVocabulary from "./core"
import validationVocabulary from "./validation"
import getApplicatorVocabulary from "./applicator"
import dynamicVocabulary from "./dynamic"
import nextVocabulary from "./next"
import unevaluatedVocabulary from "./unevaluated"
import formatVocabulary from "./format"
import {metadataVocabulary, contentVocabulary} from "./metadata"
const draft2020Vocabularies: Vocabulary[] = [
dynamicVocabulary,
coreVocabulary,
validationVocabulary,
getApplicatorVocabulary(true),
formatVocabulary,
metadataVocabulary,
contentVocabulary,
nextVocabulary,
unevaluatedVocabulary,
]
export default draft2020Vocabularies

17
my-app/node_modules/ajv/lib/vocabularies/draft7.ts generated vendored Executable file
View file

@ -0,0 +1,17 @@
import type {Vocabulary} from "../types"
import coreVocabulary from "./core"
import validationVocabulary from "./validation"
import getApplicatorVocabulary from "./applicator"
import formatVocabulary from "./format"
import {metadataVocabulary, contentVocabulary} from "./metadata"
const draft7Vocabularies: Vocabulary[] = [
coreVocabulary,
validationVocabulary,
getApplicatorVocabulary(),
formatVocabulary,
metadataVocabulary,
contentVocabulary,
]
export default draft7Vocabularies

View file

@ -0,0 +1,31 @@
import type {CodeKeywordDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, getProperty, Code} from "../../compile/codegen"
import N from "../../compile/names"
import {SchemaEnv, compileSchema} from "../../compile"
import {getValidate} from "../core/ref"
const def: CodeKeywordDefinition = {
keyword: "$dynamicAnchor",
schemaType: "string",
code: (cxt) => dynamicAnchor(cxt, cxt.schema),
}
export function dynamicAnchor(cxt: KeywordCxt, anchor: string): void {
const {gen, it} = cxt
it.schemaEnv.root.dynamicAnchors[anchor] = true
const v = _`${N.dynamicAnchors}${getProperty(anchor)}`
const validate = it.errSchemaPath === "#" ? it.validateName : _getValidate(cxt)
gen.if(_`!${v}`, () => gen.assign(v, validate))
}
function _getValidate(cxt: KeywordCxt): Code {
const {schemaEnv, schema, self} = cxt.it
const {root, baseId, localRefs, meta} = schemaEnv.root
const {schemaId} = self.opts
const sch = new SchemaEnv({schema, schemaId, root, baseId, localRefs, meta})
compileSchema.call(self, sch)
return getValidate(cxt, sch)
}
export default def

View file

@ -0,0 +1,51 @@
import type {CodeKeywordDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, getProperty, Code, Name} from "../../compile/codegen"
import N from "../../compile/names"
import {callRef} from "../core/ref"
const def: CodeKeywordDefinition = {
keyword: "$dynamicRef",
schemaType: "string",
code: (cxt) => dynamicRef(cxt, cxt.schema),
}
export function dynamicRef(cxt: KeywordCxt, ref: string): void {
const {gen, keyword, it} = cxt
if (ref[0] !== "#") throw new Error(`"${keyword}" only supports hash fragment reference`)
const anchor = ref.slice(1)
if (it.allErrors) {
_dynamicRef()
} else {
const valid = gen.let("valid", false)
_dynamicRef(valid)
cxt.ok(valid)
}
function _dynamicRef(valid?: Name): void {
// TODO the assumption here is that `recursiveRef: #` always points to the root
// of the schema object, which is not correct, because there may be $id that
// makes # point to it, and the target schema may not contain dynamic/recursiveAnchor.
// Because of that 2 tests in recursiveRef.json fail.
// This is a similar problem to #815 (`$id` doesn't alter resolution scope for `{ "$ref": "#" }`).
// (This problem is not tested in JSON-Schema-Test-Suite)
if (it.schemaEnv.root.dynamicAnchors[anchor]) {
const v = gen.let("_v", _`${N.dynamicAnchors}${getProperty(anchor)}`)
gen.if(v, _callRef(v, valid), _callRef(it.validateName, valid))
} else {
_callRef(it.validateName, valid)()
}
}
function _callRef(validate: Code, valid?: Name): () => void {
return valid
? () =>
gen.block(() => {
callRef(cxt, validate)
gen.let(valid, true)
})
: () => callRef(cxt, validate)
}
}
export default def

9
my-app/node_modules/ajv/lib/vocabularies/dynamic/index.ts generated vendored Executable file
View file

@ -0,0 +1,9 @@
import type {Vocabulary} from "../../types"
import dynamicAnchor from "./dynamicAnchor"
import dynamicRef from "./dynamicRef"
import recursiveAnchor from "./recursiveAnchor"
import recursiveRef from "./recursiveRef"
const dynamic: Vocabulary = [dynamicAnchor, dynamicRef, recursiveAnchor, recursiveRef]
export default dynamic

View file

@ -0,0 +1,14 @@
import type {CodeKeywordDefinition} from "../../types"
import {dynamicAnchor} from "./dynamicAnchor"
import {checkStrictMode} from "../../compile/util"
const def: CodeKeywordDefinition = {
keyword: "$recursiveAnchor",
schemaType: "boolean",
code(cxt) {
if (cxt.schema) dynamicAnchor(cxt, "")
else checkStrictMode(cxt.it, "$recursiveAnchor: false is ignored")
},
}
export default def

View file

@ -0,0 +1,10 @@
import type {CodeKeywordDefinition} from "../../types"
import {dynamicRef} from "./dynamicRef"
const def: CodeKeywordDefinition = {
keyword: "$recursiveRef",
schemaType: "string",
code: (cxt) => dynamicRef(cxt, cxt.schema),
}
export default def

18
my-app/node_modules/ajv/lib/vocabularies/errors.ts generated vendored Executable file
View file

@ -0,0 +1,18 @@
import type {TypeError} from "../compile/validate/dataType"
import type {ApplicatorKeywordError} from "./applicator"
import type {ValidationKeywordError} from "./validation"
import type {FormatError} from "./format/format"
import type {UnevaluatedPropertiesError} from "./unevaluated/unevaluatedProperties"
import type {UnevaluatedItemsError} from "./unevaluated/unevaluatedItems"
import type {DependentRequiredError} from "./validation/dependentRequired"
import type {DiscriminatorError} from "./discriminator"
export type DefinedError =
| TypeError
| ApplicatorKeywordError
| ValidationKeywordError
| FormatError
| UnevaluatedPropertiesError
| UnevaluatedItemsError
| DependentRequiredError
| DiscriminatorError

120
my-app/node_modules/ajv/lib/vocabularies/format/format.ts generated vendored Executable file
View file

@ -0,0 +1,120 @@
import type {
AddedFormat,
FormatValidator,
AsyncFormatValidator,
CodeKeywordDefinition,
KeywordErrorDefinition,
ErrorObject,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, nil, or, Code, getProperty, regexpCode} from "../../compile/codegen"
type FormatValidate =
| FormatValidator<string>
| FormatValidator<number>
| AsyncFormatValidator<string>
| AsyncFormatValidator<number>
| RegExp
| string
| true
export type FormatError = ErrorObject<"format", {format: string}, string | {$data: string}>
const error: KeywordErrorDefinition = {
message: ({schemaCode}) => str`must match format "${schemaCode}"`,
params: ({schemaCode}) => _`{format: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: "format",
type: ["number", "string"],
schemaType: "string",
$data: true,
error,
code(cxt: KeywordCxt, ruleType?: string) {
const {gen, data, $data, schema, schemaCode, it} = cxt
const {opts, errSchemaPath, schemaEnv, self} = it
if (!opts.validateFormats) return
if ($data) validate$DataFormat()
else validateFormat()
function validate$DataFormat(): void {
const fmts = gen.scopeValue("formats", {
ref: self.formats,
code: opts.code.formats,
})
const fDef = gen.const("fDef", _`${fmts}[${schemaCode}]`)
const fType = gen.let("fType")
const format = gen.let("format")
// TODO simplify
gen.if(
_`typeof ${fDef} == "object" && !(${fDef} instanceof RegExp)`,
() => gen.assign(fType, _`${fDef}.type || "string"`).assign(format, _`${fDef}.validate`),
() => gen.assign(fType, _`"string"`).assign(format, fDef)
)
cxt.fail$data(or(unknownFmt(), invalidFmt()))
function unknownFmt(): Code {
if (opts.strictSchema === false) return nil
return _`${schemaCode} && !${format}`
}
function invalidFmt(): Code {
const callFormat = schemaEnv.$async
? _`(${fDef}.async ? await ${format}(${data}) : ${format}(${data}))`
: _`${format}(${data})`
const validData = _`(typeof ${format} == "function" ? ${callFormat} : ${format}.test(${data}))`
return _`${format} && ${format} !== true && ${fType} === ${ruleType} && !${validData}`
}
}
function validateFormat(): void {
const formatDef: AddedFormat | undefined = self.formats[schema]
if (!formatDef) {
unknownFormat()
return
}
if (formatDef === true) return
const [fmtType, format, fmtRef] = getFormat(formatDef)
if (fmtType === ruleType) cxt.pass(validCondition())
function unknownFormat(): void {
if (opts.strictSchema === false) {
self.logger.warn(unknownMsg())
return
}
throw new Error(unknownMsg())
function unknownMsg(): string {
return `unknown format "${schema as string}" ignored in schema at path "${errSchemaPath}"`
}
}
function getFormat(fmtDef: AddedFormat): [string, FormatValidate, Code] {
const code =
fmtDef instanceof RegExp
? regexpCode(fmtDef)
: opts.code.formats
? _`${opts.code.formats}${getProperty(schema)}`
: undefined
const fmt = gen.scopeValue("formats", {key: schema, ref: fmtDef, code})
if (typeof fmtDef == "object" && !(fmtDef instanceof RegExp)) {
return [fmtDef.type || "string", fmtDef.validate, _`${fmt}.validate`]
}
return ["string", fmtDef, fmt]
}
function validCondition(): Code {
if (typeof formatDef == "object" && !(formatDef instanceof RegExp) && formatDef.async) {
if (!schemaEnv.$async) throw new Error("async format in sync schema")
return _`await ${fmtRef}(${data})`
}
return typeof format == "function" ? _`${fmtRef}(${data})` : _`${fmtRef}.test(${data})`
}
}
},
}
export default def

6
my-app/node_modules/ajv/lib/vocabularies/format/index.ts generated vendored Executable file
View file

@ -0,0 +1,6 @@
import type {Vocabulary} from "../../types"
import formatKeyword from "./format"
const format: Vocabulary = [formatKeyword]
export default format

View file

@ -0,0 +1,89 @@
import type {CodeKeywordDefinition, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, not, getProperty, Name} from "../../compile/codegen"
import {checkMetadata} from "./metadata"
import {checkNullableObject} from "./nullable"
import {typeErrorMessage, typeErrorParams, _JTDTypeError} from "./error"
import {DiscrError, DiscrErrorObj} from "../discriminator/types"
export type JTDDiscriminatorError =
| _JTDTypeError<"discriminator", "object", string>
| DiscrErrorObj<DiscrError.Tag>
| DiscrErrorObj<DiscrError.Mapping>
const error: KeywordErrorDefinition = {
message: (cxt) => {
const {schema, params} = cxt
return params.discrError
? params.discrError === DiscrError.Tag
? `tag "${schema}" must be string`
: `value of tag "${schema}" must be in mapping`
: typeErrorMessage(cxt, "object")
},
params: (cxt) => {
const {schema, params} = cxt
return params.discrError
? _`{error: ${params.discrError}, tag: ${schema}, tagValue: ${params.tag}}`
: typeErrorParams(cxt, "object")
},
}
const def: CodeKeywordDefinition = {
keyword: "discriminator",
schemaType: "string",
implements: ["mapping"],
error,
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {gen, data, schema, parentSchema} = cxt
const [valid, cond] = checkNullableObject(cxt, data)
gen.if(cond)
validateDiscriminator()
gen.elseIf(not(valid))
cxt.error()
gen.endIf()
cxt.ok(valid)
function validateDiscriminator(): void {
const tag = gen.const("tag", _`${data}${getProperty(schema)}`)
gen.if(_`${tag} === undefined`)
cxt.error(false, {discrError: DiscrError.Tag, tag})
gen.elseIf(_`typeof ${tag} == "string"`)
validateMapping(tag)
gen.else()
cxt.error(false, {discrError: DiscrError.Tag, tag}, {instancePath: schema})
gen.endIf()
}
function validateMapping(tag: Name): void {
gen.if(false)
for (const tagValue in parentSchema.mapping) {
gen.elseIf(_`${tag} === ${tagValue}`)
gen.assign(valid, applyTagSchema(tagValue))
}
gen.else()
cxt.error(
false,
{discrError: DiscrError.Mapping, tag},
{instancePath: schema, schemaPath: "mapping", parentSchema: true}
)
gen.endIf()
}
function applyTagSchema(schemaProp: string): Name {
const _valid = gen.name("valid")
cxt.subschema(
{
keyword: "mapping",
schemaProp,
jtdDiscriminator: schema,
},
_valid
)
return _valid
}
},
}
export default def

32
my-app/node_modules/ajv/lib/vocabularies/jtd/elements.ts generated vendored Executable file
View file

@ -0,0 +1,32 @@
import type {CodeKeywordDefinition, SchemaObject} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {alwaysValidSchema} from "../../compile/util"
import {validateArray} from "../code"
import {_, not} from "../../compile/codegen"
import {checkMetadata} from "./metadata"
import {checkNullable} from "./nullable"
import {typeError, _JTDTypeError} from "./error"
export type JTDElementsError = _JTDTypeError<"elements", "array", SchemaObject>
const def: CodeKeywordDefinition = {
keyword: "elements",
schemaType: "object",
error: typeError("array"),
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {gen, data, schema, it} = cxt
if (alwaysValidSchema(it, schema)) return
const [valid] = checkNullable(cxt)
gen.if(not(valid), () =>
gen.if(
_`Array.isArray(${data})`,
() => gen.assign(valid, validateArray(cxt)),
() => cxt.error()
)
)
cxt.ok(valid)
},
}
export default def

45
my-app/node_modules/ajv/lib/vocabularies/jtd/enum.ts generated vendored Executable file
View file

@ -0,0 +1,45 @@
import type {CodeKeywordDefinition, KeywordErrorDefinition, ErrorObject} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, or, and, Code} from "../../compile/codegen"
import {checkMetadata} from "./metadata"
import {checkNullable} from "./nullable"
export type JTDEnumError = ErrorObject<"enum", {allowedValues: string[]}, string[]>
const error: KeywordErrorDefinition = {
message: "must be equal to one of the allowed values",
params: ({schemaCode}) => _`{allowedValues: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: "enum",
schemaType: "array",
error,
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {gen, data, schema, schemaValue, parentSchema, it} = cxt
if (schema.length === 0) throw new Error("enum must have non-empty array")
if (schema.length !== new Set(schema).size) throw new Error("enum items must be unique")
let valid: Code
const isString = _`typeof ${data} == "string"`
if (schema.length >= it.opts.loopEnum) {
let cond: Code
;[valid, cond] = checkNullable(cxt, isString)
gen.if(cond, loopEnum)
} else {
/* istanbul ignore if */
if (!Array.isArray(schema)) throw new Error("ajv implementation error")
valid = and(isString, or(...schema.map((value: string) => _`${data} === ${value}`)))
if (parentSchema.nullable) valid = or(_`${data} === null`, valid)
}
cxt.pass(valid)
function loopEnum(): void {
gen.forOf("v", schemaValue as Code, (v) =>
gen.if(_`${valid} = ${data} === ${v}`, () => gen.break())
)
}
},
}
export default def

23
my-app/node_modules/ajv/lib/vocabularies/jtd/error.ts generated vendored Executable file
View file

@ -0,0 +1,23 @@
import type {KeywordErrorDefinition, KeywordErrorCxt, ErrorObject} from "../../types"
import {_, Code} from "../../compile/codegen"
export type _JTDTypeError<K extends string, T extends string, S> = ErrorObject<
K,
{type: T; nullable: boolean},
S
>
export function typeError(t: string): KeywordErrorDefinition {
return {
message: (cxt) => typeErrorMessage(cxt, t),
params: (cxt) => typeErrorParams(cxt, t),
}
}
export function typeErrorMessage({parentSchema}: KeywordErrorCxt, t: string): string {
return parentSchema?.nullable ? `must be ${t} or null` : `must be ${t}`
}
export function typeErrorParams({parentSchema}: KeywordErrorCxt, t: string): Code {
return _`{type: ${t}, nullable: ${!!parentSchema?.nullable}}`
}

37
my-app/node_modules/ajv/lib/vocabularies/jtd/index.ts generated vendored Executable file
View file

@ -0,0 +1,37 @@
import type {Vocabulary} from "../../types"
import refKeyword from "./ref"
import typeKeyword, {JTDTypeError} from "./type"
import enumKeyword, {JTDEnumError} from "./enum"
import elements, {JTDElementsError} from "./elements"
import properties, {JTDPropertiesError} from "./properties"
import optionalProperties from "./optionalProperties"
import discriminator, {JTDDiscriminatorError} from "./discriminator"
import values, {JTDValuesError} from "./values"
import union from "./union"
import metadata from "./metadata"
const jtdVocabulary: Vocabulary = [
"definitions",
refKeyword,
typeKeyword,
enumKeyword,
elements,
properties,
optionalProperties,
discriminator,
values,
union,
metadata,
{keyword: "additionalProperties", schemaType: "boolean"},
{keyword: "nullable", schemaType: "boolean"},
]
export default jtdVocabulary
export type JTDErrorObject =
| JTDTypeError
| JTDEnumError
| JTDElementsError
| JTDPropertiesError
| JTDDiscriminatorError
| JTDValuesError

24
my-app/node_modules/ajv/lib/vocabularies/jtd/metadata.ts generated vendored Executable file
View file

@ -0,0 +1,24 @@
import {KeywordCxt} from "../../ajv"
import type {CodeKeywordDefinition} from "../../types"
import {alwaysValidSchema} from "../../compile/util"
const def: CodeKeywordDefinition = {
keyword: "metadata",
schemaType: "object",
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {gen, schema, it} = cxt
if (alwaysValidSchema(it, schema)) return
const valid = gen.name("valid")
cxt.subschema({keyword: "metadata", jtdMetadata: true}, valid)
cxt.ok(valid)
},
}
export function checkMetadata({it, keyword}: KeywordCxt, metadata?: boolean): void {
if (it.jtdMetadata !== metadata) {
throw new Error(`JTD: "${keyword}" cannot be used in this schema location`)
}
}
export default def

21
my-app/node_modules/ajv/lib/vocabularies/jtd/nullable.ts generated vendored Executable file
View file

@ -0,0 +1,21 @@
import type {KeywordCxt} from "../../compile/validate"
import {_, not, nil, Code, Name} from "../../compile/codegen"
export function checkNullable(
{gen, data, parentSchema}: KeywordCxt,
cond: Code = nil
): [Name, Code] {
const valid = gen.name("valid")
if (parentSchema.nullable) {
gen.let(valid, _`${data} === null`)
cond = not(valid)
} else {
gen.let(valid, false)
}
return [valid, cond]
}
export function checkNullableObject(cxt: KeywordCxt, cond: Code): [Name, Code] {
const [valid, cond_] = checkNullable(cxt, cond)
return [valid, _`${cond_} && typeof ${cxt.data} == "object" && !Array.isArray(${cxt.data})`]
}

View file

@ -0,0 +1,15 @@
import type {CodeKeywordDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {validateProperties, error} from "./properties"
const def: CodeKeywordDefinition = {
keyword: "optionalProperties",
schemaType: "object",
error,
code(cxt: KeywordCxt) {
if (cxt.parentSchema.properties) return
validateProperties(cxt)
},
}
export default def

184
my-app/node_modules/ajv/lib/vocabularies/jtd/properties.ts generated vendored Executable file
View file

@ -0,0 +1,184 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
SchemaObject,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {propertyInData, allSchemaProperties, isOwnProperty} from "../code"
import {alwaysValidSchema, schemaRefOrVal} from "../../compile/util"
import {_, and, not, Code, Name} from "../../compile/codegen"
import {checkMetadata} from "./metadata"
import {checkNullableObject} from "./nullable"
import {typeErrorMessage, typeErrorParams, _JTDTypeError} from "./error"
enum PropError {
Additional = "additional",
Missing = "missing",
}
type PropKeyword = "properties" | "optionalProperties"
type PropSchema = {[P in string]?: SchemaObject}
export type JTDPropertiesError =
| _JTDTypeError<PropKeyword, "object", PropSchema>
| ErrorObject<PropKeyword, {error: PropError.Additional; additionalProperty: string}, PropSchema>
| ErrorObject<PropKeyword, {error: PropError.Missing; missingProperty: string}, PropSchema>
export const error: KeywordErrorDefinition = {
message: (cxt) => {
const {params} = cxt
return params.propError
? params.propError === PropError.Additional
? "must NOT have additional properties"
: `must have property '${params.missingProperty}'`
: typeErrorMessage(cxt, "object")
},
params: (cxt) => {
const {params} = cxt
return params.propError
? params.propError === PropError.Additional
? _`{error: ${params.propError}, additionalProperty: ${params.additionalProperty}}`
: _`{error: ${params.propError}, missingProperty: ${params.missingProperty}}`
: typeErrorParams(cxt, "object")
},
}
const def: CodeKeywordDefinition = {
keyword: "properties",
schemaType: "object",
error,
code: validateProperties,
}
// const error: KeywordErrorDefinition = {
// message: "should NOT have additional properties",
// params: ({params}) => _`{additionalProperty: ${params.additionalProperty}}`,
// }
export function validateProperties(cxt: KeywordCxt): void {
checkMetadata(cxt)
const {gen, data, parentSchema, it} = cxt
const {additionalProperties, nullable} = parentSchema
if (it.jtdDiscriminator && nullable) throw new Error("JTD: nullable inside discriminator mapping")
if (commonProperties()) {
throw new Error("JTD: properties and optionalProperties have common members")
}
const [allProps, properties] = schemaProperties("properties")
const [allOptProps, optProperties] = schemaProperties("optionalProperties")
if (properties.length === 0 && optProperties.length === 0 && additionalProperties) {
return
}
const [valid, cond] =
it.jtdDiscriminator === undefined
? checkNullableObject(cxt, data)
: [gen.let("valid", false), true]
gen.if(cond, () =>
gen.assign(valid, true).block(() => {
validateProps(properties, "properties", true)
validateProps(optProperties, "optionalProperties")
if (!additionalProperties) validateAdditional()
})
)
cxt.pass(valid)
function commonProperties(): boolean {
const props = parentSchema.properties as Record<string, any> | undefined
const optProps = parentSchema.optionalProperties as Record<string, any> | undefined
if (!(props && optProps)) return false
for (const p in props) {
if (Object.prototype.hasOwnProperty.call(optProps, p)) return true
}
return false
}
function schemaProperties(keyword: string): [string[], string[]] {
const schema = parentSchema[keyword]
const allPs = schema ? allSchemaProperties(schema) : []
if (it.jtdDiscriminator && allPs.some((p) => p === it.jtdDiscriminator)) {
throw new Error(`JTD: discriminator tag used in ${keyword}`)
}
const ps = allPs.filter((p) => !alwaysValidSchema(it, schema[p]))
return [allPs, ps]
}
function validateProps(props: string[], keyword: string, required?: boolean): void {
const _valid = gen.var("valid")
for (const prop of props) {
gen.if(
propertyInData(gen, data, prop, it.opts.ownProperties),
() => applyPropertySchema(prop, keyword, _valid),
() => missingProperty(prop)
)
cxt.ok(_valid)
}
function missingProperty(prop: string): void {
if (required) {
gen.assign(_valid, false)
cxt.error(false, {propError: PropError.Missing, missingProperty: prop}, {schemaPath: prop})
} else {
gen.assign(_valid, true)
}
}
}
function applyPropertySchema(prop: string, keyword: string, _valid: Name): void {
cxt.subschema(
{
keyword,
schemaProp: prop,
dataProp: prop,
},
_valid
)
}
function validateAdditional(): void {
gen.forIn("key", data, (key: Name) => {
const addProp = isAdditional(key, allProps, "properties", it.jtdDiscriminator)
const addOptProp = isAdditional(key, allOptProps, "optionalProperties")
const extra =
addProp === true ? addOptProp : addOptProp === true ? addProp : and(addProp, addOptProp)
gen.if(extra, () => {
if (it.opts.removeAdditional) {
gen.code(_`delete ${data}[${key}]`)
} else {
cxt.error(
false,
{propError: PropError.Additional, additionalProperty: key},
{instancePath: key, parentSchema: true}
)
if (!it.opts.allErrors) gen.break()
}
})
})
}
function isAdditional(
key: Name,
props: string[],
keyword: string,
jtdDiscriminator?: string
): Code | true {
let additional: Code | boolean
if (props.length > 8) {
// TODO maybe an option instead of hard-coded 8?
const propsSchema = schemaRefOrVal(it, parentSchema[keyword], keyword)
additional = not(isOwnProperty(gen, propsSchema as Code, key))
if (jtdDiscriminator !== undefined) {
additional = and(additional, _`${key} !== ${jtdDiscriminator}`)
}
} else if (props.length || jtdDiscriminator !== undefined) {
const ps = jtdDiscriminator === undefined ? props : [jtdDiscriminator].concat(props)
additional = and(...ps.map((p) => _`${key} !== ${p}`))
} else {
additional = true
}
return additional
}
}
export default def

76
my-app/node_modules/ajv/lib/vocabularies/jtd/ref.ts generated vendored Executable file
View file

@ -0,0 +1,76 @@
import type {CodeKeywordDefinition, AnySchemaObject} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {compileSchema, SchemaEnv} from "../../compile"
import {_, not, nil, stringify} from "../../compile/codegen"
import MissingRefError from "../../compile/ref_error"
import N from "../../compile/names"
import {getValidate, callRef} from "../core/ref"
import {checkMetadata} from "./metadata"
const def: CodeKeywordDefinition = {
keyword: "ref",
schemaType: "string",
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {gen, data, schema: ref, parentSchema, it} = cxt
const {
schemaEnv: {root},
} = it
const valid = gen.name("valid")
if (parentSchema.nullable) {
gen.var(valid, _`${data} === null`)
gen.if(not(valid), validateJtdRef)
} else {
gen.var(valid, false)
validateJtdRef()
}
cxt.ok(valid)
function validateJtdRef(): void {
const refSchema = (root.schema as AnySchemaObject).definitions?.[ref]
if (!refSchema) {
throw new MissingRefError(it.opts.uriResolver, "", ref, `No definition ${ref}`)
}
if (hasRef(refSchema) || !it.opts.inlineRefs) callValidate(refSchema)
else inlineRefSchema(refSchema)
}
function callValidate(schema: AnySchemaObject): void {
const sch = compileSchema.call(
it.self,
new SchemaEnv({schema, root, schemaPath: `/definitions/${ref}`})
)
const v = getValidate(cxt, sch)
const errsCount = gen.const("_errs", N.errors)
callRef(cxt, v, sch, sch.$async)
gen.assign(valid, _`${errsCount} === ${N.errors}`)
}
function inlineRefSchema(schema: AnySchemaObject): void {
const schName = gen.scopeValue(
"schema",
it.opts.code.source === true ? {ref: schema, code: stringify(schema)} : {ref: schema}
)
cxt.subschema(
{
schema,
dataTypes: [],
schemaPath: nil,
topSchemaRef: schName,
errSchemaPath: `/definitions/${ref}`,
},
valid
)
}
},
}
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

75
my-app/node_modules/ajv/lib/vocabularies/jtd/type.ts generated vendored Executable file
View file

@ -0,0 +1,75 @@
import type {CodeKeywordDefinition, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, nil, or, Code} from "../../compile/codegen"
import validTimestamp from "../../runtime/timestamp"
import {useFunc} from "../../compile/util"
import {checkMetadata} from "./metadata"
import {typeErrorMessage, typeErrorParams, _JTDTypeError} from "./error"
export type JTDTypeError = _JTDTypeError<"type", JTDType, JTDType>
export type IntType = "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32"
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],
}
export type JTDType = "boolean" | "string" | "timestamp" | "float32" | "float64" | IntType
const error: KeywordErrorDefinition = {
message: (cxt) => typeErrorMessage(cxt, cxt.schema),
params: (cxt) => typeErrorParams(cxt, cxt.schema),
}
function timestampCode(cxt: KeywordCxt): Code {
const {gen, data, it} = cxt
const {timestamp, allowDate} = it.opts
if (timestamp === "date") return _`${data} instanceof Date `
const vts = useFunc(gen, validTimestamp)
const allowDateArg = allowDate ? _`, true` : nil
const validString = _`typeof ${data} == "string" && ${vts}(${data}${allowDateArg})`
return timestamp === "string" ? validString : or(_`${data} instanceof Date`, validString)
}
const def: CodeKeywordDefinition = {
keyword: "type",
schemaType: "string",
error,
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {data, schema, parentSchema, it} = cxt
let cond: Code
switch (schema) {
case "boolean":
case "string":
cond = _`typeof ${data} == ${schema}`
break
case "timestamp": {
cond = timestampCode(cxt)
break
}
case "float32":
case "float64":
cond = _`typeof ${data} == "number"`
break
default: {
const sch = schema as IntType
cond = _`typeof ${data} == "number" && isFinite(${data}) && !(${data} % 1)`
if (!it.opts.int32range && (sch === "int32" || sch === "uint32")) {
if (sch === "uint32") cond = _`${cond} && ${data} >= 0`
} else {
const [min, max] = intRange[sch]
cond = _`${cond} && ${data} >= ${min} && ${data} <= ${max}`
}
}
}
cxt.pass(parentSchema.nullable ? or(_`${data} === null`, cond) : cond)
},
}
export default def

12
my-app/node_modules/ajv/lib/vocabularies/jtd/union.ts generated vendored Executable file
View file

@ -0,0 +1,12 @@
import type {CodeKeywordDefinition} from "../../types"
import {validateUnion} from "../code"
const def: CodeKeywordDefinition = {
keyword: "union",
schemaType: "array",
trackErrors: true,
code: validateUnion,
error: {message: "must match a schema in union"},
}
export default def

58
my-app/node_modules/ajv/lib/vocabularies/jtd/values.ts generated vendored Executable file
View file

@ -0,0 +1,58 @@
import type {CodeKeywordDefinition, SchemaObject} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {alwaysValidSchema, Type} from "../../compile/util"
import {not, or, Name} from "../../compile/codegen"
import {checkMetadata} from "./metadata"
import {checkNullableObject} from "./nullable"
import {typeError, _JTDTypeError} from "./error"
export type JTDValuesError = _JTDTypeError<"values", "object", SchemaObject>
const def: CodeKeywordDefinition = {
keyword: "values",
schemaType: "object",
error: typeError("object"),
code(cxt: KeywordCxt) {
checkMetadata(cxt)
const {gen, data, schema, it} = cxt
const [valid, cond] = checkNullableObject(cxt, data)
if (alwaysValidSchema(it, schema)) {
gen.if(not(or(cond, valid)), () => cxt.error())
} else {
gen.if(cond)
gen.assign(valid, validateMap())
gen.elseIf(not(valid))
cxt.error()
gen.endIf()
}
cxt.ok(valid)
function validateMap(): Name | boolean {
const _valid = gen.name("valid")
if (it.allErrors) {
const validMap = gen.let("valid", true)
validateValues(() => gen.assign(validMap, false))
return validMap
}
gen.var(_valid, true)
validateValues(() => gen.break())
return _valid
function validateValues(notValid: () => void): void {
gen.forIn("key", data, (key) => {
cxt.subschema(
{
keyword: "values",
dataProp: key,
dataPropType: Type.Str,
},
_valid
)
gen.if(not(_valid), notValid)
})
}
}
},
}
export default def

17
my-app/node_modules/ajv/lib/vocabularies/metadata.ts generated vendored Executable file
View file

@ -0,0 +1,17 @@
import type {Vocabulary} from "../types"
export const metadataVocabulary: Vocabulary = [
"title",
"description",
"default",
"deprecated",
"readOnly",
"writeOnly",
"examples",
]
export const contentVocabulary: Vocabulary = [
"contentMediaType",
"contentEncoding",
"contentSchema",
]

8
my-app/node_modules/ajv/lib/vocabularies/next.ts generated vendored Executable file
View file

@ -0,0 +1,8 @@
import type {Vocabulary} from "../types"
import dependentRequired from "./validation/dependentRequired"
import dependentSchemas from "./applicator/dependentSchemas"
import limitContains from "./validation/limitContains"
const next: Vocabulary = [dependentRequired, dependentSchemas, limitContains]
export default next

View file

@ -0,0 +1,7 @@
import type {Vocabulary} from "../../types"
import unevaluatedProperties from "./unevaluatedProperties"
import unevaluatedItems from "./unevaluatedItems"
const unevaluated: Vocabulary = [unevaluatedProperties, unevaluatedItems]
export default unevaluated

View file

@ -0,0 +1,47 @@
import type {
CodeKeywordDefinition,
ErrorObject,
KeywordErrorDefinition,
AnySchema,
} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, not, Name} from "../../compile/codegen"
import {alwaysValidSchema, Type} from "../../compile/util"
export type UnevaluatedItemsError = ErrorObject<"unevaluatedItems", {limit: number}, AnySchema>
const error: KeywordErrorDefinition = {
message: ({params: {len}}) => str`must NOT have more than ${len} items`,
params: ({params: {len}}) => _`{limit: ${len}}`,
}
const def: CodeKeywordDefinition = {
keyword: "unevaluatedItems",
type: "array",
schemaType: ["boolean", "object"],
error,
code(cxt: KeywordCxt) {
const {gen, schema, data, it} = cxt
const items = it.items || 0
if (items === true) return
const len = gen.const("len", _`${data}.length`)
if (schema === false) {
cxt.setParams({len: items})
cxt.fail(_`${len} > ${items}`)
} else if (typeof schema == "object" && !alwaysValidSchema(it, schema)) {
const valid = gen.var("valid", _`${len} <= ${items}`)
gen.if(not(valid), () => validateItems(valid, items))
cxt.ok(valid)
}
it.items = true
function validateItems(valid: Name, from: Name | number): void {
gen.forRange("i", from, len, (i) => {
cxt.subschema({keyword: "unevaluatedItems", dataProp: i, dataPropType: Type.Num}, valid)
if (!it.allErrors) gen.if(not(valid), () => gen.break())
})
}
},
}
export default def

View file

@ -0,0 +1,85 @@
import type {
CodeKeywordDefinition,
KeywordErrorDefinition,
ErrorObject,
AnySchema,
} from "../../types"
import {_, not, and, Name, Code} from "../../compile/codegen"
import {alwaysValidSchema, Type} from "../../compile/util"
import N from "../../compile/names"
export type UnevaluatedPropertiesError = ErrorObject<
"unevaluatedProperties",
{unevaluatedProperty: string},
AnySchema
>
const error: KeywordErrorDefinition = {
message: "must NOT have unevaluated properties",
params: ({params}) => _`{unevaluatedProperty: ${params.unevaluatedProperty}}`,
}
const def: CodeKeywordDefinition = {
keyword: "unevaluatedProperties",
type: "object",
schemaType: ["boolean", "object"],
trackErrors: true,
error,
code(cxt) {
const {gen, schema, data, errsCount, it} = cxt
/* istanbul ignore if */
if (!errsCount) throw new Error("ajv implementation error")
const {allErrors, props} = it
if (props instanceof Name) {
gen.if(_`${props} !== true`, () =>
gen.forIn("key", data, (key: Name) =>
gen.if(unevaluatedDynamic(props, key), () => unevaluatedPropCode(key))
)
)
} else if (props !== true) {
gen.forIn("key", data, (key: Name) =>
props === undefined
? unevaluatedPropCode(key)
: gen.if(unevaluatedStatic(props, key), () => unevaluatedPropCode(key))
)
}
it.props = true
cxt.ok(_`${errsCount} === ${N.errors}`)
function unevaluatedPropCode(key: Name): void {
if (schema === false) {
cxt.setParams({unevaluatedProperty: key})
cxt.error()
if (!allErrors) gen.break()
return
}
if (!alwaysValidSchema(it, schema)) {
const valid = gen.name("valid")
cxt.subschema(
{
keyword: "unevaluatedProperties",
dataProp: key,
dataPropType: Type.Str,
},
valid
)
if (!allErrors) gen.if(not(valid), () => gen.break())
}
}
function unevaluatedDynamic(evaluatedProps: Name, key: Name): Code {
return _`!${evaluatedProps} || !${evaluatedProps}[${key}]`
}
function unevaluatedStatic(evaluatedProps: {[K in string]?: true}, key: Name): Code {
const ps: Code[] = []
for (const p in evaluatedProps) {
if (evaluatedProps[p] === true) ps.push(_`${key} !== ${p}`)
}
return and(...ps)
}
},
}
export default def

28
my-app/node_modules/ajv/lib/vocabularies/validation/const.ts generated vendored Executable file
View file

@ -0,0 +1,28 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_} from "../../compile/codegen"
import {useFunc} from "../../compile/util"
import equal from "../../runtime/equal"
export type ConstError = ErrorObject<"const", {allowedValue: any}>
const error: KeywordErrorDefinition = {
message: "must be equal to constant",
params: ({schemaCode}) => _`{allowedValue: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: "const",
$data: true,
error,
code(cxt: KeywordCxt) {
const {gen, data, $data, schemaCode, schema} = cxt
if ($data || (schema && typeof schema == "object")) {
cxt.fail$data(_`!${useFunc(gen, equal)}(${data}, ${schemaCode})`)
} else {
cxt.fail(_`${schema} !== ${data}`)
}
},
}
export default def

View file

@ -0,0 +1,23 @@
import type {CodeKeywordDefinition, ErrorObject} from "../../types"
import {
validatePropertyDeps,
error,
DependenciesErrorParams,
PropertyDependencies,
} from "../applicator/dependencies"
export type DependentRequiredError = ErrorObject<
"dependentRequired",
DependenciesErrorParams,
PropertyDependencies
>
const def: CodeKeywordDefinition = {
keyword: "dependentRequired",
type: "object",
schemaType: "object",
error,
code: (cxt) => validatePropertyDeps(cxt),
}
export default def

54
my-app/node_modules/ajv/lib/vocabularies/validation/enum.ts generated vendored Executable file
View file

@ -0,0 +1,54 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, or, Name, Code} from "../../compile/codegen"
import {useFunc} from "../../compile/util"
import equal from "../../runtime/equal"
export type EnumError = ErrorObject<"enum", {allowedValues: any[]}, any[] | {$data: string}>
const error: KeywordErrorDefinition = {
message: "must be equal to one of the allowed values",
params: ({schemaCode}) => _`{allowedValues: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: "enum",
schemaType: "array",
$data: true,
error,
code(cxt: KeywordCxt) {
const {gen, data, $data, schema, schemaCode, it} = cxt
if (!$data && schema.length === 0) throw new Error("enum must have non-empty array")
const useLoop = schema.length >= it.opts.loopEnum
let eql: Name | undefined
const getEql = (): Name => (eql ??= useFunc(gen, equal))
let valid: Code
if (useLoop || $data) {
valid = gen.let("valid")
cxt.block$data(valid, loopEnum)
} else {
/* istanbul ignore if */
if (!Array.isArray(schema)) throw new Error("ajv implementation error")
const vSchema = gen.const("vSchema", schemaCode)
valid = or(...schema.map((_x: unknown, i: number) => equalCode(vSchema, i)))
}
cxt.pass(valid)
function loopEnum(): void {
gen.assign(valid, false)
gen.forOf("v", schemaCode as Code, (v) =>
gen.if(_`${getEql()}(${data}, ${v})`, () => gen.assign(valid, true).break())
)
}
function equalCode(vSchema: Name, i: number): Code {
const sch = schema[i]
return typeof sch === "object" && sch !== null
? _`${getEql()}(${data}, ${vSchema}[${i}])`
: _`${data} === ${sch}`
}
},
}
export default def

49
my-app/node_modules/ajv/lib/vocabularies/validation/index.ts generated vendored Executable file
View file

@ -0,0 +1,49 @@
import type {ErrorObject, Vocabulary} from "../../types"
import limitNumber, {LimitNumberError} from "./limitNumber"
import multipleOf, {MultipleOfError} from "./multipleOf"
import limitLength from "./limitLength"
import pattern, {PatternError} from "./pattern"
import limitProperties from "./limitProperties"
import required, {RequiredError} from "./required"
import limitItems from "./limitItems"
import uniqueItems, {UniqueItemsError} from "./uniqueItems"
import constKeyword, {ConstError} from "./const"
import enumKeyword, {EnumError} from "./enum"
const validation: Vocabulary = [
// number
limitNumber,
multipleOf,
// string
limitLength,
pattern,
// object
limitProperties,
required,
// array
limitItems,
uniqueItems,
// any
{keyword: "type", schemaType: ["string", "array"]},
{keyword: "nullable", schemaType: "boolean"},
constKeyword,
enumKeyword,
]
export default validation
type LimitError = ErrorObject<
"maxItems" | "minItems" | "minProperties" | "maxProperties" | "minLength" | "maxLength",
{limit: number},
number | {$data: string}
>
export type ValidationKeywordError =
| LimitError
| LimitNumberError
| MultipleOfError
| PatternError
| RequiredError
| UniqueItemsError
| ConstError
| EnumError

View file

@ -0,0 +1,16 @@
import type {CodeKeywordDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {checkStrictMode} from "../../compile/util"
const def: CodeKeywordDefinition = {
keyword: ["maxContains", "minContains"],
type: "array",
schemaType: "number",
code({keyword, parentSchema, it}: KeywordCxt) {
if (parentSchema.contains === undefined) {
checkStrictMode(it, `"${keyword}" without "contains" is ignored`)
}
},
}
export default def

View file

@ -0,0 +1,26 @@
import type {CodeKeywordDefinition, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, operators} from "../../compile/codegen"
const error: KeywordErrorDefinition = {
message({keyword, schemaCode}) {
const comp = keyword === "maxItems" ? "more" : "fewer"
return str`must NOT have ${comp} than ${schemaCode} items`
},
params: ({schemaCode}) => _`{limit: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: ["maxItems", "minItems"],
type: "array",
schemaType: "number",
$data: true,
error,
code(cxt: KeywordCxt) {
const {keyword, data, schemaCode} = cxt
const op = keyword === "maxItems" ? operators.GT : operators.LT
cxt.fail$data(_`${data}.length ${op} ${schemaCode}`)
},
}
export default def

View file

@ -0,0 +1,30 @@
import type {CodeKeywordDefinition, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, operators} from "../../compile/codegen"
import {useFunc} from "../../compile/util"
import ucs2length from "../../runtime/ucs2length"
const error: KeywordErrorDefinition = {
message({keyword, schemaCode}) {
const comp = keyword === "maxLength" ? "more" : "fewer"
return str`must NOT have ${comp} than ${schemaCode} characters`
},
params: ({schemaCode}) => _`{limit: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: ["maxLength", "minLength"],
type: "string",
schemaType: "number",
$data: true,
error,
code(cxt: KeywordCxt) {
const {keyword, data, schemaCode, it} = cxt
const op = keyword === "maxLength" ? operators.GT : operators.LT
const len =
it.opts.unicode === false ? _`${data}.length` : _`${useFunc(cxt.gen, ucs2length)}(${data})`
cxt.fail$data(_`${len} ${op} ${schemaCode}`)
},
}
export default def

View file

@ -0,0 +1,42 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, operators, Code} from "../../compile/codegen"
const ops = operators
type Kwd = "maximum" | "minimum" | "exclusiveMaximum" | "exclusiveMinimum"
type Comparison = "<=" | ">=" | "<" | ">"
const KWDs: {[K in Kwd]: {okStr: Comparison; ok: Code; fail: Code}} = {
maximum: {okStr: "<=", ok: ops.LTE, fail: ops.GT},
minimum: {okStr: ">=", ok: ops.GTE, fail: ops.LT},
exclusiveMaximum: {okStr: "<", ok: ops.LT, fail: ops.GTE},
exclusiveMinimum: {okStr: ">", ok: ops.GT, fail: ops.LTE},
}
export type LimitNumberError = ErrorObject<
Kwd,
{limit: number; comparison: Comparison},
number | {$data: string}
>
const error: KeywordErrorDefinition = {
message: ({keyword, schemaCode}) => str`must be ${KWDs[keyword as Kwd].okStr} ${schemaCode}`,
params: ({keyword, schemaCode}) =>
_`{comparison: ${KWDs[keyword as Kwd].okStr}, limit: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: Object.keys(KWDs),
type: "number",
schemaType: "number",
$data: true,
error,
code(cxt: KeywordCxt) {
const {keyword, data, schemaCode} = cxt
cxt.fail$data(_`${data} ${KWDs[keyword as Kwd].fail} ${schemaCode} || isNaN(${data})`)
},
}
export default def

View file

@ -0,0 +1,26 @@
import type {CodeKeywordDefinition, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str, operators} from "../../compile/codegen"
const error: KeywordErrorDefinition = {
message({keyword, schemaCode}) {
const comp = keyword === "maxProperties" ? "more" : "fewer"
return str`must NOT have ${comp} than ${schemaCode} properties`
},
params: ({schemaCode}) => _`{limit: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: ["maxProperties", "minProperties"],
type: "object",
schemaType: "number",
$data: true,
error,
code(cxt: KeywordCxt) {
const {keyword, data, schemaCode} = cxt
const op = keyword === "maxProperties" ? operators.GT : operators.LT
cxt.fail$data(_`Object.keys(${data}).length ${op} ${schemaCode}`)
},
}
export default def

View file

@ -0,0 +1,34 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {_, str} from "../../compile/codegen"
export type MultipleOfError = ErrorObject<
"multipleOf",
{multipleOf: number},
number | {$data: string}
>
const error: KeywordErrorDefinition = {
message: ({schemaCode}) => str`must be multiple of ${schemaCode}`,
params: ({schemaCode}) => _`{multipleOf: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: "multipleOf",
type: "number",
schemaType: "number",
$data: true,
error,
code(cxt: KeywordCxt) {
const {gen, data, schemaCode, it} = cxt
// const bdt = bad$DataType(schemaCode, <string>def.schemaType, $data)
const prec = it.opts.multipleOfPrecision
const res = gen.let("res")
const invalid = prec
? _`Math.abs(Math.round(${res}) - ${res}) > 1e-${prec}`
: _`${res} !== parseInt(${res})`
cxt.fail$data(_`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${invalid}))`)
},
}
export default def

View file

@ -0,0 +1,28 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {usePattern} from "../code"
import {_, str} from "../../compile/codegen"
export type PatternError = ErrorObject<"pattern", {pattern: string}, string | {$data: string}>
const error: KeywordErrorDefinition = {
message: ({schemaCode}) => str`must match pattern "${schemaCode}"`,
params: ({schemaCode}) => _`{pattern: ${schemaCode}}`,
}
const def: CodeKeywordDefinition = {
keyword: "pattern",
type: "string",
schemaType: "string",
$data: true,
error,
code(cxt: KeywordCxt) {
const {data, $data, schema, schemaCode, it} = cxt
// TODO regexp should be wrapped in try/catchs
const u = it.opts.unicodeRegExp ? "u" : ""
const regExp = $data ? _`(new RegExp(${schemaCode}, ${u}))` : usePattern(cxt, schema)
cxt.fail$data(_`!${regExp}.test(${data})`)
},
}
export default def

View file

@ -0,0 +1,98 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {
checkReportMissingProp,
checkMissingProp,
reportMissingProp,
propertyInData,
noPropertyInData,
} from "../code"
import {_, str, nil, not, Name, Code} from "../../compile/codegen"
import {checkStrictMode} from "../../compile/util"
export type RequiredError = ErrorObject<
"required",
{missingProperty: string},
string[] | {$data: string}
>
const error: KeywordErrorDefinition = {
message: ({params: {missingProperty}}) => str`must have required property '${missingProperty}'`,
params: ({params: {missingProperty}}) => _`{missingProperty: ${missingProperty}}`,
}
const def: CodeKeywordDefinition = {
keyword: "required",
type: "object",
schemaType: "array",
$data: true,
error,
code(cxt: KeywordCxt) {
const {gen, schema, schemaCode, data, $data, it} = cxt
const {opts} = it
if (!$data && schema.length === 0) return
const useLoop = schema.length >= opts.loopRequired
if (it.allErrors) allErrorsMode()
else exitOnErrorMode()
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 {
if (useLoop || $data) {
cxt.block$data(nil, loopAllRequired)
} else {
for (const prop of schema) {
checkReportMissingProp(cxt, prop)
}
}
}
function exitOnErrorMode(): void {
const missing = gen.let("missing")
if (useLoop || $data) {
const valid = gen.let("valid", true)
cxt.block$data(valid, () => loopUntilMissing(missing, valid))
cxt.ok(valid)
} else {
gen.if(checkMissingProp(cxt, schema, missing))
reportMissingProp(cxt, missing)
gen.else()
}
}
function loopAllRequired(): void {
gen.forOf("prop", schemaCode as Code, (prop) => {
cxt.setParams({missingProperty: prop})
gen.if(noPropertyInData(gen, data, prop, opts.ownProperties), () => cxt.error())
})
}
function loopUntilMissing(missing: Name, valid: Name): void {
cxt.setParams({missingProperty: missing})
gen.forOf(
missing,
schemaCode as Code,
() => {
gen.assign(valid, propertyInData(gen, data, missing, opts.ownProperties))
gen.if(not(valid), () => {
cxt.error()
gen.break()
})
},
nil
)
}
},
}
export default def

View file

@ -0,0 +1,79 @@
import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
import type {KeywordCxt} from "../../compile/validate"
import {checkDataTypes, getSchemaTypes, DataType} from "../../compile/validate/dataType"
import {_, str, Name} from "../../compile/codegen"
import {useFunc} from "../../compile/util"
import equal from "../../runtime/equal"
export type UniqueItemsError = ErrorObject<
"uniqueItems",
{i: number; j: number},
boolean | {$data: string}
>
const error: KeywordErrorDefinition = {
message: ({params: {i, j}}) =>
str`must NOT have duplicate items (items ## ${j} and ${i} are identical)`,
params: ({params: {i, j}}) => _`{i: ${i}, j: ${j}}`,
}
const def: CodeKeywordDefinition = {
keyword: "uniqueItems",
type: "array",
schemaType: "boolean",
$data: true,
error,
code(cxt: KeywordCxt) {
const {gen, data, $data, schema, parentSchema, schemaCode, it} = cxt
if (!$data && !schema) return
const valid = gen.let("valid")
const itemTypes = parentSchema.items ? getSchemaTypes(parentSchema.items) : []
cxt.block$data(valid, validateUniqueItems, _`${schemaCode} === false`)
cxt.ok(valid)
function validateUniqueItems(): void {
const i = gen.let("i", _`${data}.length`)
const j = gen.let("j")
cxt.setParams({i, j})
gen.assign(valid, true)
gen.if(_`${i} > 1`, () => (canOptimize() ? loopN : loopN2)(i, j))
}
function canOptimize(): boolean {
return itemTypes.length > 0 && !itemTypes.some((t) => t === "object" || t === "array")
}
function loopN(i: Name, j: Name): void {
const item = gen.name("item")
const wrongType = checkDataTypes(itemTypes, item, it.opts.strictNumbers, DataType.Wrong)
const indices = gen.const("indices", _`{}`)
gen.for(_`;${i}--;`, () => {
gen.let(item, _`${data}[${i}]`)
gen.if(wrongType, _`continue`)
if (itemTypes.length > 1) gen.if(_`typeof ${item} == "string"`, _`${item} += "_"`)
gen
.if(_`typeof ${indices}[${item}] == "number"`, () => {
gen.assign(j, _`${indices}[${item}]`)
cxt.error()
gen.assign(valid, false).break()
})
.code(_`${indices}[${item}] = ${i}`)
})
}
function loopN2(i: Name, j: Name): void {
const eql = useFunc(gen, equal)
const outer = gen.name("outer")
gen.label(outer).for(_`;${i}--;`, () =>
gen.for(_`${j} = ${i}; ${j}--;`, () =>
gen.if(_`${eql}(${data}[${i}], ${data}[${j}])`, () => {
cxt.error()
gen.assign(valid, false).break(outer)
})
)
)
}
},
}
export default def