source: trip-planner-front/node_modules/ajv/lib/vocabularies/format/format.ts

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 3.9 KB
Line 
1import type {
2 AddedFormat,
3 FormatValidator,
4 AsyncFormatValidator,
5 CodeKeywordDefinition,
6 KeywordErrorDefinition,
7 ErrorObject,
8} from "../../types"
9import type {KeywordCxt} from "../../compile/validate"
10import {_, str, nil, or, Code, getProperty, regexpCode} from "../../compile/codegen"
11
12type FormatValidate =
13 | FormatValidator<string>
14 | FormatValidator<number>
15 | AsyncFormatValidator<string>
16 | AsyncFormatValidator<number>
17 | RegExp
18 | string
19 | true
20
21export type FormatError = ErrorObject<"format", {format: string}, string | {$data: string}>
22
23const error: KeywordErrorDefinition = {
24 message: ({schemaCode}) => str`must match format "${schemaCode}"`,
25 params: ({schemaCode}) => _`{format: ${schemaCode}}`,
26}
27
28const def: CodeKeywordDefinition = {
29 keyword: "format",
30 type: ["number", "string"],
31 schemaType: "string",
32 $data: true,
33 error,
34 code(cxt: KeywordCxt, ruleType?: string) {
35 const {gen, data, $data, schema, schemaCode, it} = cxt
36 const {opts, errSchemaPath, schemaEnv, self} = it
37 if (!opts.validateFormats) return
38
39 if ($data) validate$DataFormat()
40 else validateFormat()
41
42 function validate$DataFormat(): void {
43 const fmts = gen.scopeValue("formats", {
44 ref: self.formats,
45 code: opts.code.formats,
46 })
47 const fDef = gen.const("fDef", _`${fmts}[${schemaCode}]`)
48 const fType = gen.let("fType")
49 const format = gen.let("format")
50 // TODO simplify
51 gen.if(
52 _`typeof ${fDef} == "object" && !(${fDef} instanceof RegExp)`,
53 () => gen.assign(fType, _`${fDef}.type || "string"`).assign(format, _`${fDef}.validate`),
54 () => gen.assign(fType, _`"string"`).assign(format, fDef)
55 )
56 cxt.fail$data(or(unknownFmt(), invalidFmt()))
57
58 function unknownFmt(): Code {
59 if (opts.strictSchema === false) return nil
60 return _`${schemaCode} && !${format}`
61 }
62
63 function invalidFmt(): Code {
64 const callFormat = schemaEnv.$async
65 ? _`(${fDef}.async ? await ${format}(${data}) : ${format}(${data}))`
66 : _`${format}(${data})`
67 const validData = _`(typeof ${format} == "function" ? ${callFormat} : ${format}.test(${data}))`
68 return _`${format} && ${format} !== true && ${fType} === ${ruleType} && !${validData}`
69 }
70 }
71
72 function validateFormat(): void {
73 const formatDef: AddedFormat | undefined = self.formats[schema]
74 if (!formatDef) {
75 unknownFormat()
76 return
77 }
78 if (formatDef === true) return
79 const [fmtType, format, fmtRef] = getFormat(formatDef)
80 if (fmtType === ruleType) cxt.pass(validCondition())
81
82 function unknownFormat(): void {
83 if (opts.strictSchema === false) {
84 self.logger.warn(unknownMsg())
85 return
86 }
87 throw new Error(unknownMsg())
88
89 function unknownMsg(): string {
90 return `unknown format "${schema as string}" ignored in schema at path "${errSchemaPath}"`
91 }
92 }
93
94 function getFormat(fmtDef: AddedFormat): [string, FormatValidate, Code] {
95 const code =
96 fmtDef instanceof RegExp
97 ? regexpCode(fmtDef)
98 : opts.code.formats
99 ? _`${opts.code.formats}${getProperty(schema)}`
100 : undefined
101 const fmt = gen.scopeValue("formats", {key: schema, ref: fmtDef, code})
102 if (typeof fmtDef == "object" && !(fmtDef instanceof RegExp)) {
103 return [fmtDef.type || "string", fmtDef.validate, _`${fmt}.validate`]
104 }
105
106 return ["string", fmtDef, fmt]
107 }
108
109 function validCondition(): Code {
110 if (typeof formatDef == "object" && !(formatDef instanceof RegExp) && formatDef.async) {
111 if (!schemaEnv.$async) throw new Error("async format in sync schema")
112 return _`await ${fmtRef}(${data})`
113 }
114 return typeof format == "function" ? _`${fmtRef}(${data})` : _`${fmtRef}.test(${data})`
115 }
116 }
117 },
118}
119
120export default def
Note: See TracBrowser for help on using the repository browser.