ajv
Version:
Another JSON Schema Validator
86 lines (75 loc) • 2.91 kB
text/typescript
import type {AnySchema, SchemaMap} from "../types"
import type {SchemaCxt} from "../compile"
import type KeywordCxt from "../compile/context"
import {CodeGen, _, or, nil, strConcat, getProperty, Code, Name} from "../compile/codegen"
import {alwaysValidSchema} from "../compile/util"
import N from "../compile/names"
export function checkReportMissingProp(cxt: KeywordCxt, prop: string): void {
const {gen, data, it} = cxt
gen.if(noPropertyInData(data, prop, it.opts.ownProperties), () => {
cxt.setParams({missingProperty: _`${prop}`}, true)
cxt.error()
})
}
export function checkMissingProp(
{data, it: {opts}}: KeywordCxt,
properties: string[],
missing: Name
): Code {
return or(
...properties.map(
(prop) => _`${noPropertyInData(data, prop, opts.ownProperties)} && (${missing} = ${prop})`
)
)
}
export function reportMissingProp(cxt: KeywordCxt, missing: Name): void {
cxt.setParams({missingProperty: missing}, true)
cxt.error()
}
function isOwnProperty(data: Name, property: Name | string): Code {
return _`Object.prototype.hasOwnProperty.call(${data}, ${property})`
}
export function propertyInData(data: Name, property: Name | string, ownProperties?: boolean): Code {
const cond = _`${data}${getProperty(property)} !== undefined`
return ownProperties ? _`${cond} && ${isOwnProperty(data, property)}` : cond
}
export function noPropertyInData(
data: Name,
property: Name | string,
ownProperties?: boolean
): Code {
const cond = _`${data}${getProperty(property)} === undefined`
return ownProperties ? _`${cond} || !${isOwnProperty(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.dataPath, strConcat(N.dataPath, 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})`
}
export function usePattern(gen: CodeGen, pattern: string): Name {
return gen.scopeValue("pattern", {
key: pattern,
ref: new RegExp(pattern, "u"),
code: _`new RegExp(${pattern}, "u")`,
})
}