massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / table / node_modules / ajv / lib / vocabularies / format / format.ts
1 import type {
2   AddedFormat,
3   FormatValidator,
4   AsyncFormatValidator,
5   CodeKeywordDefinition,
6   KeywordErrorDefinition,
7   ErrorObject,
8 } from "../../types"
9 import type {KeywordCxt} from "../../compile/validate"
10 import {_, str, nil, or, Code, getProperty, regexpCode} from "../../compile/codegen"
11
12 type FormatValidate =
13   | FormatValidator<string>
14   | FormatValidator<number>
15   | AsyncFormatValidator<string>
16   | AsyncFormatValidator<number>
17   | RegExp
18   | string
19   | true
20
21 export type FormatError = ErrorObject<"format", {format: string}, string | {$data: string}>
22
23 const error: KeywordErrorDefinition = {
24   message: ({schemaCode}) => str`must match format "${schemaCode}"`,
25   params: ({schemaCode}) => _`{format: ${schemaCode}}`,
26 }
27
28 const 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
120 export default def