.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / table / node_modules / ajv / lib / vocabularies / core / ref.ts
1 import type {CodeKeywordDefinition, AnySchema} from "../../types"
2 import type {KeywordCxt} from "../../compile/validate"
3 import MissingRefError from "../../compile/ref_error"
4 import {callValidateCode} from "../code"
5 import {_, nil, stringify, Code, Name} from "../../compile/codegen"
6 import N from "../../compile/names"
7 import {SchemaEnv, resolveRef} from "../../compile"
8 import {mergeEvaluated} from "../../compile/util"
9
10 const def: CodeKeywordDefinition = {
11   keyword: "$ref",
12   schemaType: "string",
13   code(cxt: KeywordCxt): void {
14     const {gen, schema: $ref, it} = cxt
15     const {baseId, schemaEnv: env, validateName, opts, self} = it
16     const {root} = env
17     if (($ref === "#" || $ref === "#/") && baseId === root.baseId) return callRootRef()
18     const schOrEnv = resolveRef.call(self, root, baseId, $ref)
19     if (schOrEnv === undefined) throw new MissingRefError(baseId, $ref)
20     if (schOrEnv instanceof SchemaEnv) return callValidate(schOrEnv)
21     return inlineRefSchema(schOrEnv)
22
23     function callRootRef(): void {
24       if (env === root) return callRef(cxt, validateName, env, env.$async)
25       const rootName = gen.scopeValue("root", {ref: root})
26       return callRef(cxt, _`${rootName}.validate`, root, root.$async)
27     }
28
29     function callValidate(sch: SchemaEnv): void {
30       const v = getValidate(cxt, sch)
31       callRef(cxt, v, sch, sch.$async)
32     }
33
34     function inlineRefSchema(sch: AnySchema): void {
35       const schName = gen.scopeValue(
36         "schema",
37         opts.code.source === true ? {ref: sch, code: stringify(sch)} : {ref: sch}
38       )
39       const valid = gen.name("valid")
40       const schCxt = cxt.subschema(
41         {
42           schema: sch,
43           dataTypes: [],
44           schemaPath: nil,
45           topSchemaRef: schName,
46           errSchemaPath: $ref,
47         },
48         valid
49       )
50       cxt.mergeEvaluated(schCxt)
51       cxt.ok(valid)
52     }
53   },
54 }
55
56 export function getValidate(cxt: KeywordCxt, sch: SchemaEnv): Code {
57   const {gen} = cxt
58   return sch.validate
59     ? gen.scopeValue("validate", {ref: sch.validate})
60     : _`${gen.scopeValue("wrapper", {ref: sch})}.validate`
61 }
62
63 export function callRef(cxt: KeywordCxt, v: Code, sch?: SchemaEnv, $async?: boolean): void {
64   const {gen, it} = cxt
65   const {allErrors, schemaEnv: env, opts} = it
66   const passCxt = opts.passContext ? N.this : nil
67   if ($async) callAsyncRef()
68   else callSyncRef()
69
70   function callAsyncRef(): void {
71     if (!env.$async) throw new Error("async schema referenced by sync schema")
72     const valid = gen.let("valid")
73     gen.try(
74       () => {
75         gen.code(_`await ${callValidateCode(cxt, v, passCxt)}`)
76         addEvaluatedFrom(v) // TODO will not work with async, it has to be returned with the result
77         if (!allErrors) gen.assign(valid, true)
78       },
79       (e) => {
80         gen.if(_`!(${e} instanceof ${it.ValidationError as Name})`, () => gen.throw(e))
81         addErrorsFrom(e)
82         if (!allErrors) gen.assign(valid, false)
83       }
84     )
85     cxt.ok(valid)
86   }
87
88   function callSyncRef(): void {
89     cxt.result(
90       callValidateCode(cxt, v, passCxt),
91       () => addEvaluatedFrom(v),
92       () => addErrorsFrom(v)
93     )
94   }
95
96   function addErrorsFrom(source: Code): void {
97     const errs = _`${source}.errors`
98     gen.assign(N.vErrors, _`${N.vErrors} === null ? ${errs} : ${N.vErrors}.concat(${errs})`) // TODO tagged
99     gen.assign(N.errors, _`${N.vErrors}.length`)
100   }
101
102   function addEvaluatedFrom(source: Code): void {
103     if (!it.opts.unevaluated) return
104     const schEvaluated = sch?.validate?.evaluated
105     // TODO refactor
106     if (it.props !== true) {
107       if (schEvaluated && !schEvaluated.dynamicProps) {
108         if (schEvaluated.props !== undefined) {
109           it.props = mergeEvaluated.props(gen, schEvaluated.props, it.props)
110         }
111       } else {
112         const props = gen.var("props", _`${source}.evaluated.props`)
113         it.props = mergeEvaluated.props(gen, props, it.props, Name)
114       }
115     }
116     if (it.items !== true) {
117       if (schEvaluated && !schEvaluated.dynamicItems) {
118         if (schEvaluated.items !== undefined) {
119           it.items = mergeEvaluated.items(gen, schEvaluated.items, it.items)
120         }
121       } else {
122         const items = gen.var("items", _`${source}.evaluated.items`)
123         it.items = mergeEvaluated.items(gen, items, it.items, Name)
124       }
125     }
126   }
127 }
128
129 export default def