aboutsummaryrefslogtreecommitdiff
path: root/sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts
diff options
context:
space:
mode:
authorDanijel Andjelkovic <adanijel99@gmail.com>2022-03-01 21:54:41 +0100
committerDanijel Andjelkovic <adanijel99@gmail.com>2022-03-01 21:54:41 +0100
commit6c8128f9fd5a5d0be115806c35a21b3d683df8d6 (patch)
treef46c2f6b3b9b294ff32bd75c08ccdc9e7a8cc4ef /sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts
parent2400b84e95913665da6279114168148444b8f9ab (diff)
parent7d3640f824f46490b47bd95f1c5a16644f712068 (diff)
Merge branch 'dev' of http://gitlab.pmf.kg.ac.rs/igrannonica/neuronstellar into logo
Diffstat (limited to 'sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts')
-rw-r--r--sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts411
1 files changed, 411 insertions, 0 deletions
diff --git a/sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts b/sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts
new file mode 100644
index 00000000..cd2611e7
--- /dev/null
+++ b/sandbox/testAppNevena/Front/node_modules/ajv/lib/compile/jtd/parse.ts
@@ -0,0 +1,411 @@
+import type Ajv from "../../core"
+import type {SchemaObject} from "../../types"
+import {jtdForms, JTDForm, SchemaObjectMap} from "./types"
+import {SchemaEnv, getCompilingSchema} from ".."
+import {_, str, and, or, nil, not, CodeGen, Code, Name, SafeExpr} from "../codegen"
+import MissingRefError from "../ref_error"
+import N from "../names"
+import {hasPropFunc} from "../../vocabularies/code"
+import {hasRef} from "../../vocabularies/jtd/ref"
+import {intRange, IntType} from "../../vocabularies/jtd/type"
+import {parseJson, parseJsonNumber, parseJsonString} from "../../runtime/parseJson"
+import {useFunc} from "../util"
+import validTimestamp from "../../runtime/timestamp"
+
+type GenParse = (cxt: ParseCxt) => void
+
+const genParse: {[F in JTDForm]: GenParse} = {
+ elements: parseElements,
+ values: parseValues,
+ discriminator: parseDiscriminator,
+ properties: parseProperties,
+ optionalProperties: parseProperties,
+ enum: parseEnum,
+ type: parseType,
+ ref: parseRef,
+}
+
+interface ParseCxt {
+ readonly gen: CodeGen
+ readonly self: Ajv // current Ajv instance
+ readonly schemaEnv: SchemaEnv
+ readonly definitions: SchemaObjectMap
+ schema: SchemaObject
+ data: Code
+ parseName: Name
+ char: Name
+}
+
+export default function compileParser(
+ this: Ajv,
+ sch: SchemaEnv,
+ definitions: SchemaObjectMap
+): SchemaEnv {
+ const _sch = getCompilingSchema.call(this, sch)
+ if (_sch) return _sch
+ const {es5, lines} = this.opts.code
+ const {ownProperties} = this.opts
+ const gen = new CodeGen(this.scope, {es5, lines, ownProperties})
+ const parseName = gen.scopeName("parse")
+ const cxt: ParseCxt = {
+ self: this,
+ gen,
+ schema: sch.schema as SchemaObject,
+ schemaEnv: sch,
+ definitions,
+ data: N.data,
+ parseName,
+ char: gen.name("c"),
+ }
+
+ let sourceCode: string | undefined
+ try {
+ this._compilations.add(sch)
+ sch.parseName = parseName
+ parserFunction(cxt)
+ gen.optimize(this.opts.code.optimize)
+ const parseFuncCode = gen.toString()
+ sourceCode = `${gen.scopeRefs(N.scope)}return ${parseFuncCode}`
+ const makeParse = new Function(`${N.scope}`, sourceCode)
+ const parse: (json: string) => unknown = makeParse(this.scope.get())
+ this.scope.value(parseName, {ref: parse})
+ sch.parse = parse
+ } catch (e) {
+ if (sourceCode) this.logger.error("Error compiling parser, function code:", sourceCode)
+ delete sch.parse
+ delete sch.parseName
+ throw e
+ } finally {
+ this._compilations.delete(sch)
+ }
+ return sch
+}
+
+const undef = _`undefined`
+
+function parserFunction(cxt: ParseCxt): void {
+ const {gen, parseName, char} = cxt
+ gen.func(parseName, _`${N.json}, ${N.jsonPos}, ${N.jsonPart}`, false, () => {
+ gen.let(N.data)
+ gen.let(char)
+ gen.assign(_`${parseName}.message`, undef)
+ gen.assign(_`${parseName}.position`, undef)
+ gen.assign(N.jsonPos, _`${N.jsonPos} || 0`)
+ gen.const(N.jsonLen, _`${N.json}.length`)
+ parseCode(cxt)
+ skipWhitespace(cxt)
+ gen.if(N.jsonPart, () => {
+ gen.assign(_`${parseName}.position`, N.jsonPos)
+ gen.return(N.data)
+ })
+ gen.if(_`${N.jsonPos} === ${N.jsonLen}`, () => gen.return(N.data))
+ jsonSyntaxError(cxt)
+ })
+}
+
+function parseCode(cxt: ParseCxt): void {
+ let form: JTDForm | undefined
+ for (const key of jtdForms) {
+ if (key in cxt.schema) {
+ form = key
+ break
+ }
+ }
+ if (form) parseNullable(cxt, genParse[form])
+ else parseEmpty(cxt)
+}
+
+const parseBoolean = parseBooleanToken(true, parseBooleanToken(false, jsonSyntaxError))
+
+function parseNullable(cxt: ParseCxt, parseForm: GenParse): void {
+ const {gen, schema, data} = cxt
+ if (!schema.nullable) return parseForm(cxt)
+ tryParseToken(cxt, "null", parseForm, () => gen.assign(data, null))
+}
+
+function parseElements(cxt: ParseCxt): void {
+ const {gen, schema, data} = cxt
+ parseToken(cxt, "[")
+ const ix = gen.let("i", 0)
+ gen.assign(data, _`[]`)
+ parseItems(cxt, "]", () => {
+ const el = gen.let("el")
+ parseCode({...cxt, schema: schema.elements, data: el})
+ gen.assign(_`${data}[${ix}++]`, el)
+ })
+}
+
+function parseValues(cxt: ParseCxt): void {
+ const {gen, schema, data} = cxt
+ parseToken(cxt, "{")
+ gen.assign(data, _`{}`)
+ parseItems(cxt, "}", () => parseKeyValue(cxt, schema.values))
+}
+
+function parseItems(cxt: ParseCxt, endToken: string, block: () => void): void {
+ tryParseItems(cxt, endToken, block)
+ parseToken(cxt, endToken)
+}
+
+function tryParseItems(cxt: ParseCxt, endToken: string, block: () => void): void {
+ const {gen} = cxt
+ gen.for(_`;${N.jsonPos}<${N.jsonLen} && ${jsonSlice(1)}!==${endToken};`, () => {
+ block()
+ tryParseToken(cxt, ",", () => gen.break(), hasItem)
+ })
+
+ function hasItem(): void {
+ tryParseToken(cxt, endToken, () => {}, jsonSyntaxError)
+ }
+}
+
+function parseKeyValue(cxt: ParseCxt, schema: SchemaObject): void {
+ const {gen} = cxt
+ const key = gen.let("key")
+ parseString({...cxt, data: key})
+ parseToken(cxt, ":")
+ parsePropertyValue(cxt, key, schema)
+}
+
+function parseDiscriminator(cxt: ParseCxt): void {
+ const {gen, data, schema} = cxt
+ const {discriminator, mapping} = schema
+ parseToken(cxt, "{")
+ gen.assign(data, _`{}`)
+ const startPos = gen.const("pos", N.jsonPos)
+ const value = gen.let("value")
+ const tag = gen.let("tag")
+ tryParseItems(cxt, "}", () => {
+ const key = gen.let("key")
+ parseString({...cxt, data: key})
+ parseToken(cxt, ":")
+ gen.if(
+ _`${key} === ${discriminator}`,
+ () => {
+ parseString({...cxt, data: tag})
+ gen.assign(_`${data}[${key}]`, tag)
+ gen.break()
+ },
+ () => parseEmpty({...cxt, data: value}) // can be discarded/skipped
+ )
+ })
+ gen.assign(N.jsonPos, startPos)
+ gen.if(_`${tag} === undefined`)
+ parsingError(cxt, str`discriminator tag not found`)
+ for (const tagValue in mapping) {
+ gen.elseIf(_`${tag} === ${tagValue}`)
+ parseSchemaProperties({...cxt, schema: mapping[tagValue]}, discriminator)
+ }
+ gen.else()
+ parsingError(cxt, str`discriminator value not in schema`)
+ gen.endIf()
+}
+
+function parseProperties(cxt: ParseCxt): void {
+ const {gen, data} = cxt
+ parseToken(cxt, "{")
+ gen.assign(data, _`{}`)
+ parseSchemaProperties(cxt)
+}
+
+function parseSchemaProperties(cxt: ParseCxt, discriminator?: string): void {
+ const {gen, schema, data} = cxt
+ const {properties, optionalProperties, additionalProperties} = schema
+ parseItems(cxt, "}", () => {
+ const key = gen.let("key")
+ parseString({...cxt, data: key})
+ parseToken(cxt, ":")
+ gen.if(false)
+ parseDefinedProperty(cxt, key, properties)
+ parseDefinedProperty(cxt, key, optionalProperties)
+ if (discriminator) {
+ gen.elseIf(_`${key} === ${discriminator}`)
+ const tag = gen.let("tag")
+ parseString({...cxt, data: tag}) // can be discarded, it is already assigned
+ }
+ gen.else()
+ if (additionalProperties) {
+ parseEmpty({...cxt, data: _`${data}[${key}]`})
+ } else {
+ parsingError(cxt, str`property ${key} not allowed`)
+ }
+ gen.endIf()
+ })
+ if (properties) {
+ const hasProp = hasPropFunc(gen)
+ const allProps: Code = and(
+ ...Object.keys(properties).map((p): Code => _`${hasProp}.call(${data}, ${p})`)
+ )
+ gen.if(not(allProps), () => parsingError(cxt, str`missing required properties`))
+ }
+}
+
+function parseDefinedProperty(cxt: ParseCxt, key: Name, schemas: SchemaObjectMap = {}): void {
+ const {gen} = cxt
+ for (const prop in schemas) {
+ gen.elseIf(_`${key} === ${prop}`)
+ parsePropertyValue(cxt, key, schemas[prop] as SchemaObject)
+ }
+}
+
+function parsePropertyValue(cxt: ParseCxt, key: Name, schema: SchemaObject): void {
+ parseCode({...cxt, schema, data: _`${cxt.data}[${key}]`})
+}
+
+function parseType(cxt: ParseCxt): void {
+ const {gen, schema, data, self} = cxt
+ switch (schema.type) {
+ case "boolean":
+ parseBoolean(cxt)
+ break
+ case "string":
+ parseString(cxt)
+ break
+ case "timestamp": {
+ parseString(cxt)
+ const vts = useFunc(gen, validTimestamp)
+ const {allowDate, parseDate} = self.opts
+ const notValid = allowDate ? _`!${vts}(${data}, true)` : _`!${vts}(${data})`
+ const fail: Code = parseDate
+ ? or(notValid, _`(${data} = new Date(${data}), false)`, _`isNaN(${data}.valueOf())`)
+ : notValid
+ gen.if(fail, () => parsingError(cxt, str`invalid timestamp`))
+ break
+ }
+ case "float32":
+ case "float64":
+ parseNumber(cxt)
+ break
+ default: {
+ const t = schema.type as IntType
+ if (!self.opts.int32range && (t === "int32" || t === "uint32")) {
+ parseNumber(cxt, 16) // 2 ** 53 - max safe integer
+ if (t === "uint32") {
+ gen.if(_`${data} < 0`, () => parsingError(cxt, str`integer out of range`))
+ }
+ } else {
+ const [min, max, maxDigits] = intRange[t]
+ parseNumber(cxt, maxDigits)
+ gen.if(_`${data} < ${min} || ${data} > ${max}`, () =>
+ parsingError(cxt, str`integer out of range`)
+ )
+ }
+ }
+ }
+}
+
+function parseString(cxt: ParseCxt): void {
+ parseToken(cxt, '"')
+ parseWith(cxt, parseJsonString)
+}
+
+function parseEnum(cxt: ParseCxt): void {
+ const {gen, data, schema} = cxt
+ const enumSch = schema.enum
+ parseToken(cxt, '"')
+ // TODO loopEnum
+ gen.if(false)
+ for (const value of enumSch) {
+ const valueStr = JSON.stringify(value).slice(1) // remove starting quote
+ gen.elseIf(_`${jsonSlice(valueStr.length)} === ${valueStr}`)
+ gen.assign(data, str`${value}`)
+ gen.add(N.jsonPos, valueStr.length)
+ }
+ gen.else()
+ jsonSyntaxError(cxt)
+ gen.endIf()
+}
+
+function parseNumber(cxt: ParseCxt, maxDigits?: number): void {
+ const {gen} = cxt
+ skipWhitespace(cxt)
+ gen.if(
+ _`"-0123456789".indexOf(${jsonSlice(1)}) < 0`,
+ () => jsonSyntaxError(cxt),
+ () => parseWith(cxt, parseJsonNumber, maxDigits)
+ )
+}
+
+function parseBooleanToken(bool: boolean, fail: GenParse): GenParse {
+ return (cxt) => {
+ const {gen, data} = cxt
+ tryParseToken(
+ cxt,
+ `${bool}`,
+ () => fail(cxt),
+ () => gen.assign(data, bool)
+ )
+ }
+}
+
+function parseRef(cxt: ParseCxt): void {
+ const {gen, self, definitions, schema, schemaEnv} = cxt
+ const {ref} = schema
+ const refSchema = definitions[ref]
+ if (!refSchema) throw new MissingRefError("", ref, `No definition ${ref}`)
+ if (!hasRef(refSchema)) return parseCode({...cxt, schema: refSchema})
+ const {root} = schemaEnv
+ const sch = compileParser.call(self, new SchemaEnv({schema: refSchema, root}), definitions)
+ partialParse(cxt, getParser(gen, sch), true)
+}
+
+function getParser(gen: CodeGen, sch: SchemaEnv): Code {
+ return sch.parse
+ ? gen.scopeValue("parse", {ref: sch.parse})
+ : _`${gen.scopeValue("wrapper", {ref: sch})}.parse`
+}
+
+function parseEmpty(cxt: ParseCxt): void {
+ parseWith(cxt, parseJson)
+}
+
+function parseWith(cxt: ParseCxt, parseFunc: {code: string}, args?: SafeExpr): void {
+ partialParse(cxt, useFunc(cxt.gen, parseFunc), args)
+}
+
+function partialParse(cxt: ParseCxt, parseFunc: Name, args?: SafeExpr): void {
+ const {gen, data} = cxt
+ gen.assign(data, _`${parseFunc}(${N.json}, ${N.jsonPos}${args ? _`, ${args}` : nil})`)
+ gen.assign(N.jsonPos, _`${parseFunc}.position`)
+ gen.if(_`${data} === undefined`, () => parsingError(cxt, _`${parseFunc}.message`))
+}
+
+function parseToken(cxt: ParseCxt, tok: string): void {
+ tryParseToken(cxt, tok, jsonSyntaxError)
+}
+
+function tryParseToken(cxt: ParseCxt, tok: string, fail: GenParse, success?: GenParse): void {
+ const {gen} = cxt
+ const n = tok.length
+ skipWhitespace(cxt)
+ gen.if(
+ _`${jsonSlice(n)} === ${tok}`,
+ () => {
+ gen.add(N.jsonPos, n)
+ success?.(cxt)
+ },
+ () => fail(cxt)
+ )
+}
+
+function skipWhitespace({gen, char: c}: ParseCxt): void {
+ gen.code(
+ _`while((${c}=${N.json}[${N.jsonPos}],${c}===" "||${c}==="\\n"||${c}==="\\r"||${c}==="\\t"))${N.jsonPos}++;`
+ )
+}
+
+function jsonSlice(len: number | Name): Code {
+ return len === 1
+ ? _`${N.json}[${N.jsonPos}]`
+ : _`${N.json}.slice(${N.jsonPos}, ${N.jsonPos}+${len})`
+}
+
+function jsonSyntaxError(cxt: ParseCxt): void {
+ parsingError(cxt, _`"unexpected token " + ${N.json}[${N.jsonPos}]`)
+}
+
+function parsingError({gen, parseName}: ParseCxt, msg: Code): void {
+ gen.assign(_`${parseName}.message`, msg)
+ gen.assign(_`${parseName}.position`, N.jsonPos)
+ gen.return(undef)
+}