@zuplo/cli 6.71.23 → 6.71.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@fastify/fast-json-stringify-compiler/.github/dependabot.yml +42 -2
- package/node_modules/@fastify/fast-json-stringify-compiler/.github/workflows/ci.yml +6 -1
- package/node_modules/@fastify/fast-json-stringify-compiler/.github/workflows/lock-threads.yml +19 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/LICENSE +1 -1
- package/node_modules/@fastify/fast-json-stringify-compiler/README.md +1 -1
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.gitattributes +2 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.github/dependabot.yml +13 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.github/workflows/ci.yml +33 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.github/workflows/lock-threads.yml +19 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/LICENSE +22 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/README.md +742 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench-cmp-branch.js +116 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench-cmp-lib.js +339 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench-thread.js +33 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench.js +391 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/build/build-schema-validator.js +26 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/eslint.config.js +9 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/examples/example.js +81 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/examples/server.js +42 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/index.js +1308 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/location.js +24 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/merge-schemas.js +9 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/schema-validator.js +1134 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/serializer.js +141 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/standalone.js +34 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/validator.js +96 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/package.json +89 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/additionalProperties.test.js +332 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/allof.test.js +751 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/any.test.js +231 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/anyof.test.js +812 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/array.test.js +688 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/asNumber.test.js +13 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/basic.test.js +400 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/bigint.test.js +76 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/clean-cache.test.js +47 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/const.test.js +314 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/date.test.js +639 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/debug-mode.test.js +130 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/defaults.test.js +376 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/enum.test.js +37 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/fix-604.test.js +25 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/fixtures/.keep +0 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/if-then-else.test.js +540 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/inferType.test.js +92 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/infinity.test.js +55 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/integer.test.js +194 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/invalidSchema.test.js +38 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-479.test.js +57 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-793.test.js +107 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-794.test.js +177 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-836.test.js +183 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-add-comma.test.js +57 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/README.md +10 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft4/required.json +54 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft4.test.js +12 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft6/required.json +70 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft6.test.js +12 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft7/required.json +70 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft7.test.js +12 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/util.js +31 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/missing-values.test.js +88 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/multi-type-serializer.test.js +19 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/nestedObjects.test.js +63 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/nullable.test.js +543 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/oneof.test.js +510 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/patternProperties.test.js +168 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/recursion.test.js +245 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/ref.json +12 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/ref.test.js +2077 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/regex.test.js +32 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/required.test.js +204 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/requiresAjv.test.js +50 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize.test.js +141 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize2.test.js +18 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize3.test.js +17 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize4.test.js +16 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize5.test.js +16 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize6.test.js +22 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize7.test.js +68 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/side-effect.test.js +196 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/standalone-mode.test.js +219 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/string.test.js +84 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/surrogate.test.js +67 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/toJSON.test.js +203 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/typebox.test.js +36 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/typesArray.test.js +550 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/unknownFormats.test.js +27 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/webpack.test.js +50 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/types/index.d.ts +219 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/types/index.tst.ts +259 -0
- package/node_modules/@fastify/fast-json-stringify-compiler/package.json +6 -11
- package/node_modules/@fastify/fast-json-stringify-compiler/types/{index.test-d.ts → index.tst.ts} +34 -32
- package/node_modules/@protobufjs/utf8/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/utf8/index.js +29 -18
- package/node_modules/@protobufjs/utf8/package.json +2 -2
- package/node_modules/@protobufjs/utf8/tests/index.js +5 -0
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-5CYWMN74.js → chunk-D3O7C43P.js} +98 -97
- package/node_modules/@zuplo/runtime/out/esm/chunk-D3O7C43P.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/index.js.map +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +172 -0
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -1
- package/node_modules/hono/dist/adapter/bun/websocket.js +3 -1
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -1
- package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +3 -1
- package/node_modules/hono/dist/cjs/middleware/serve-static/index.js +1 -1
- package/node_modules/hono/dist/cjs/utils/body.js +12 -4
- package/node_modules/hono/dist/cjs/utils/buffer.js +2 -1
- package/node_modules/hono/dist/cjs/validator/validator.js +3 -3
- package/node_modules/hono/dist/middleware/serve-static/index.js +1 -1
- package/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +2 -2
- package/node_modules/hono/dist/types/utils/body.d.ts +1 -1
- package/node_modules/hono/dist/utils/body.js +12 -4
- package/node_modules/hono/dist/utils/buffer.js +2 -1
- package/node_modules/hono/dist/validator/validator.js +3 -3
- package/node_modules/hono/package.json +8 -7
- package/package.json +6 -6
- package/node_modules/@fastify/fast-json-stringify-compiler/.eslintrc +0 -1
- package/node_modules/@zuplo/runtime/out/esm/chunk-5CYWMN74.js.map +0 -1
- package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +0 -1
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-5CYWMN74.js.LEGAL.txt → chunk-D3O7C43P.js.LEGAL.txt} +0 -0
package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/index.js
ADDED
|
@@ -0,0 +1,1308 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint no-prototype-builtins: 0 */
|
|
4
|
+
|
|
5
|
+
const { RefResolver } = require('json-schema-ref-resolver')
|
|
6
|
+
|
|
7
|
+
const Serializer = require('./lib/serializer')
|
|
8
|
+
const Validator = require('./lib/validator')
|
|
9
|
+
const Location = require('./lib/location')
|
|
10
|
+
const validate = require('./lib/schema-validator')
|
|
11
|
+
const mergeSchemas = require('./lib/merge-schemas')
|
|
12
|
+
|
|
13
|
+
const SINGLE_TICK = /'/g
|
|
14
|
+
|
|
15
|
+
let largeArraySize = 2e4
|
|
16
|
+
let largeArrayMechanism = 'default'
|
|
17
|
+
|
|
18
|
+
const serializerFns = `
|
|
19
|
+
const {
|
|
20
|
+
asString,
|
|
21
|
+
asNumber,
|
|
22
|
+
asBoolean,
|
|
23
|
+
asDateTime,
|
|
24
|
+
asDate,
|
|
25
|
+
asTime,
|
|
26
|
+
asUnsafeString
|
|
27
|
+
} = serializer
|
|
28
|
+
|
|
29
|
+
const asInteger = serializer.asInteger.bind(serializer)
|
|
30
|
+
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
const validRoundingMethods = new Set([
|
|
34
|
+
'floor',
|
|
35
|
+
'ceil',
|
|
36
|
+
'round',
|
|
37
|
+
'trunc'
|
|
38
|
+
])
|
|
39
|
+
|
|
40
|
+
const validLargeArrayMechanisms = new Set([
|
|
41
|
+
'default',
|
|
42
|
+
'json-stringify'
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
let schemaIdCounter = 0
|
|
46
|
+
|
|
47
|
+
function isValidSchema (schema, name) {
|
|
48
|
+
if (!validate(schema)) {
|
|
49
|
+
if (name) {
|
|
50
|
+
name = `"${name}" `
|
|
51
|
+
} else {
|
|
52
|
+
name = ''
|
|
53
|
+
}
|
|
54
|
+
const first = validate.errors[0]
|
|
55
|
+
const err = new Error(`${name}schema is invalid: data${first.instancePath} ${first.message}`)
|
|
56
|
+
err.errors = isValidSchema.errors
|
|
57
|
+
throw err
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveRef (context, location) {
|
|
62
|
+
const ref = location.schema.$ref
|
|
63
|
+
|
|
64
|
+
let hashIndex = ref.indexOf('#')
|
|
65
|
+
if (hashIndex === -1) {
|
|
66
|
+
hashIndex = ref.length
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const schemaId = ref.slice(0, hashIndex) || location.schemaId
|
|
70
|
+
const jsonPointer = ref.slice(hashIndex) || '#'
|
|
71
|
+
|
|
72
|
+
const schema = context.refResolver.getSchema(schemaId, jsonPointer)
|
|
73
|
+
if (schema === null) {
|
|
74
|
+
throw new Error(`Cannot find reference "${ref}"`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const newLocation = new Location(schema, schemaId, jsonPointer)
|
|
78
|
+
if (schema.$ref !== undefined) {
|
|
79
|
+
return resolveRef(context, newLocation)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return newLocation
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getMergedLocation (context, mergedSchemaId) {
|
|
86
|
+
const mergedSchema = context.refResolver.getSchema(mergedSchemaId, '#')
|
|
87
|
+
return new Location(mergedSchema, mergedSchemaId, '#')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getSchemaId (schema, rootSchemaId) {
|
|
91
|
+
if (schema.$id && schema.$id.charAt(0) !== '#') {
|
|
92
|
+
return schema.$id
|
|
93
|
+
}
|
|
94
|
+
return rootSchemaId
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getSafeSchemaRef (context, location) {
|
|
98
|
+
let schemaRef = location.getSchemaRef() || ''
|
|
99
|
+
if (schemaRef.startsWith(context.rootSchemaId)) {
|
|
100
|
+
schemaRef = schemaRef.replace(context.rootSchemaId, '') || '#'
|
|
101
|
+
}
|
|
102
|
+
return schemaRef
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function build (schema, options) {
|
|
106
|
+
isValidSchema(schema)
|
|
107
|
+
|
|
108
|
+
options = options || {}
|
|
109
|
+
|
|
110
|
+
const context = {
|
|
111
|
+
functions: [],
|
|
112
|
+
functionsCounter: 0,
|
|
113
|
+
functionsNamesBySchema: new Map(),
|
|
114
|
+
options,
|
|
115
|
+
refResolver: new RefResolver(),
|
|
116
|
+
rootSchemaId: schema.$id || `__fjs_root_${schemaIdCounter++}`,
|
|
117
|
+
validatorSchemasIds: new Set(),
|
|
118
|
+
mergedSchemasIds: new Map(),
|
|
119
|
+
recursiveSchemas: new Set(),
|
|
120
|
+
recursivePaths: new Set(),
|
|
121
|
+
buildingSet: new Set(),
|
|
122
|
+
uid: 0
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const schemaId = getSchemaId(schema, context.rootSchemaId)
|
|
126
|
+
if (!context.refResolver.hasSchema(schemaId)) {
|
|
127
|
+
context.refResolver.addSchema(schema, context.rootSchemaId)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (options.schema) {
|
|
131
|
+
for (const key in options.schema) {
|
|
132
|
+
const schema = options.schema[key]
|
|
133
|
+
const schemaId = getSchemaId(schema, key)
|
|
134
|
+
if (!context.refResolver.hasSchema(schemaId)) {
|
|
135
|
+
isValidSchema(schema, key)
|
|
136
|
+
context.refResolver.addSchema(schema, key)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (options.rounding) {
|
|
142
|
+
if (!validRoundingMethods.has(options.rounding)) {
|
|
143
|
+
throw new Error(`Unsupported integer rounding method ${options.rounding}`)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (options.largeArrayMechanism) {
|
|
148
|
+
if (validLargeArrayMechanisms.has(options.largeArrayMechanism)) {
|
|
149
|
+
largeArrayMechanism = options.largeArrayMechanism
|
|
150
|
+
} else {
|
|
151
|
+
throw new Error(`Unsupported large array mechanism ${options.largeArrayMechanism}`)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (options.largeArraySize) {
|
|
156
|
+
const largeArraySizeType = typeof options.largeArraySize
|
|
157
|
+
let parsedNumber
|
|
158
|
+
|
|
159
|
+
if (largeArraySizeType === 'string' && Number.isFinite((parsedNumber = Number.parseInt(options.largeArraySize, 10)))) {
|
|
160
|
+
largeArraySize = parsedNumber
|
|
161
|
+
} else if (largeArraySizeType === 'number' && Number.isInteger(options.largeArraySize)) {
|
|
162
|
+
largeArraySize = options.largeArraySize
|
|
163
|
+
} else if (largeArraySizeType === 'bigint') {
|
|
164
|
+
largeArraySize = Number(options.largeArraySize)
|
|
165
|
+
} else {
|
|
166
|
+
throw new Error(`Unsupported large array size. Expected integer-like, got ${typeof options.largeArraySize} with value ${options.largeArraySize}`)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const location = new Location(schema, context.rootSchemaId)
|
|
171
|
+
detectRecursiveSchemas(context, location)
|
|
172
|
+
const code = buildValue(context, location, 'input')
|
|
173
|
+
|
|
174
|
+
let contextFunctionCode = `
|
|
175
|
+
${serializerFns}
|
|
176
|
+
const JSON_STR_BEGIN_OBJECT = '{'
|
|
177
|
+
const JSON_STR_END_OBJECT = '}'
|
|
178
|
+
const JSON_STR_BEGIN_ARRAY = '['
|
|
179
|
+
const JSON_STR_END_ARRAY = ']'
|
|
180
|
+
const JSON_STR_COMMA = ','
|
|
181
|
+
const JSON_STR_COLONS = ':'
|
|
182
|
+
const JSON_STR_QUOTE = '"'
|
|
183
|
+
const JSON_STR_EMPTY_OBJECT = JSON_STR_BEGIN_OBJECT + JSON_STR_END_OBJECT
|
|
184
|
+
const JSON_STR_EMPTY_ARRAY = JSON_STR_BEGIN_ARRAY + JSON_STR_END_ARRAY
|
|
185
|
+
const JSON_STR_EMPTY_STRING = JSON_STR_QUOTE + JSON_STR_QUOTE
|
|
186
|
+
const JSON_STR_NULL = 'null'
|
|
187
|
+
`
|
|
188
|
+
|
|
189
|
+
// If we have only the invocation of the 'anonymous0' function, we would
|
|
190
|
+
// basically just wrap the 'anonymous0' function in the 'main' function and
|
|
191
|
+
// and the overhead of the intermediate variable 'json'. We can avoid the
|
|
192
|
+
// wrapping and the unnecessary memory allocation by aliasing 'anonymous0' to
|
|
193
|
+
// 'main'
|
|
194
|
+
if (code === 'json += anonymous0(input)') {
|
|
195
|
+
contextFunctionCode += `
|
|
196
|
+
${context.functions.join('\n')}
|
|
197
|
+
const main = anonymous0
|
|
198
|
+
return main
|
|
199
|
+
`
|
|
200
|
+
} else {
|
|
201
|
+
contextFunctionCode += `
|
|
202
|
+
function main (input) {
|
|
203
|
+
let json = ''
|
|
204
|
+
${code}
|
|
205
|
+
return json
|
|
206
|
+
}
|
|
207
|
+
${context.functions.join('\n')}
|
|
208
|
+
return main
|
|
209
|
+
`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const serializer = new Serializer(options)
|
|
213
|
+
const validator = new Validator(options.ajv)
|
|
214
|
+
|
|
215
|
+
for (const schemaId of context.validatorSchemasIds) {
|
|
216
|
+
const schema = context.refResolver.getSchema(schemaId)
|
|
217
|
+
validator.addSchema(schema, schemaId)
|
|
218
|
+
|
|
219
|
+
const dependencies = context.refResolver.getSchemaDependencies(schemaId)
|
|
220
|
+
for (const [schemaId, schema] of Object.entries(dependencies)) {
|
|
221
|
+
validator.addSchema(schema, schemaId)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (options.mode === 'debug') {
|
|
226
|
+
return {
|
|
227
|
+
validator,
|
|
228
|
+
serializer,
|
|
229
|
+
code: `validator\nserializer\n${contextFunctionCode}`,
|
|
230
|
+
ajv: validator.ajv
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* eslint no-new-func: "off" */
|
|
235
|
+
const contextFunc = new Function('validator', 'serializer', contextFunctionCode)
|
|
236
|
+
|
|
237
|
+
if (options.mode === 'standalone') {
|
|
238
|
+
const buildStandaloneCode = require('./lib/standalone')
|
|
239
|
+
return buildStandaloneCode(contextFunc, context, serializer, validator)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return contextFunc(validator, serializer)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const objectKeywords = [
|
|
246
|
+
'properties',
|
|
247
|
+
'required',
|
|
248
|
+
'additionalProperties',
|
|
249
|
+
'patternProperties',
|
|
250
|
+
'maxProperties',
|
|
251
|
+
'minProperties',
|
|
252
|
+
'dependencies'
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
const arrayKeywords = [
|
|
256
|
+
'items',
|
|
257
|
+
'additionalItems',
|
|
258
|
+
'maxItems',
|
|
259
|
+
'minItems',
|
|
260
|
+
'uniqueItems',
|
|
261
|
+
'contains'
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
const stringKeywords = [
|
|
265
|
+
'maxLength',
|
|
266
|
+
'minLength',
|
|
267
|
+
'pattern'
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
const numberKeywords = [
|
|
271
|
+
'multipleOf',
|
|
272
|
+
'maximum',
|
|
273
|
+
'exclusiveMaximum',
|
|
274
|
+
'minimum',
|
|
275
|
+
'exclusiveMinimum'
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Infer type based on keyword in order to generate optimized code
|
|
280
|
+
* https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6
|
|
281
|
+
*/
|
|
282
|
+
function inferTypeByKeyword (schema) {
|
|
283
|
+
for (const keyword of objectKeywords) {
|
|
284
|
+
if (keyword in schema) return 'object'
|
|
285
|
+
}
|
|
286
|
+
for (const keyword of arrayKeywords) {
|
|
287
|
+
if (keyword in schema) return 'array'
|
|
288
|
+
}
|
|
289
|
+
for (const keyword of stringKeywords) {
|
|
290
|
+
if (keyword in schema) return 'string'
|
|
291
|
+
}
|
|
292
|
+
for (const keyword of numberKeywords) {
|
|
293
|
+
if (keyword in schema) return 'number'
|
|
294
|
+
}
|
|
295
|
+
return schema.type
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function buildExtraObjectPropertiesSerializer (context, location, addComma, objVar) {
|
|
299
|
+
const schema = location.schema
|
|
300
|
+
const propertiesKeys = Object.keys(schema.properties || {})
|
|
301
|
+
|
|
302
|
+
let code = `
|
|
303
|
+
for (const key of Object.keys(${objVar})) {
|
|
304
|
+
if (
|
|
305
|
+
${propertiesKeys.length > 0 ? propertiesKeys.map(k => `key === ${JSON.stringify(k)}`).join(' || ') + ' ||' : ''}
|
|
306
|
+
${objVar}[key] === undefined ||
|
|
307
|
+
typeof ${objVar}[key] === 'function' ||
|
|
308
|
+
typeof ${objVar}[key] === 'symbol'
|
|
309
|
+
) continue
|
|
310
|
+
const value = ${objVar}[key]
|
|
311
|
+
`
|
|
312
|
+
|
|
313
|
+
const patternPropertiesLocation = location.getPropertyLocation('patternProperties')
|
|
314
|
+
const patternPropertiesSchema = patternPropertiesLocation.schema
|
|
315
|
+
|
|
316
|
+
if (patternPropertiesSchema !== undefined) {
|
|
317
|
+
for (const propertyKey in patternPropertiesSchema) {
|
|
318
|
+
const propertyLocation = patternPropertiesLocation.getPropertyLocation(propertyKey)
|
|
319
|
+
|
|
320
|
+
code += `
|
|
321
|
+
if (/${propertyKey.replace(/\\*\//g, '\\/')}/.test(key)) {
|
|
322
|
+
${addComma}
|
|
323
|
+
json += asString(key) + JSON_STR_COLONS
|
|
324
|
+
${buildValue(context, propertyLocation, 'value')}
|
|
325
|
+
continue
|
|
326
|
+
}
|
|
327
|
+
`
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const additionalPropertiesLocation = location.getPropertyLocation('additionalProperties')
|
|
332
|
+
const additionalPropertiesSchema = additionalPropertiesLocation.schema
|
|
333
|
+
|
|
334
|
+
if (additionalPropertiesSchema !== undefined) {
|
|
335
|
+
if (additionalPropertiesSchema === true) {
|
|
336
|
+
code += `
|
|
337
|
+
${addComma}
|
|
338
|
+
json += asString(key) + JSON_STR_COLONS + JSON.stringify(value)
|
|
339
|
+
`
|
|
340
|
+
} else {
|
|
341
|
+
const propertyLocation = location.getPropertyLocation('additionalProperties')
|
|
342
|
+
code += `
|
|
343
|
+
${addComma}
|
|
344
|
+
json += asString(key) + JSON_STR_COLONS
|
|
345
|
+
${buildValue(context, propertyLocation, 'value')}
|
|
346
|
+
`
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
code += `
|
|
351
|
+
}
|
|
352
|
+
`
|
|
353
|
+
return code
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function buildInnerObject (context, location, objVar) {
|
|
357
|
+
const schema = location.schema
|
|
358
|
+
|
|
359
|
+
const propertiesLocation = location.getPropertyLocation('properties')
|
|
360
|
+
const requiredProperties = schema.required || []
|
|
361
|
+
|
|
362
|
+
// Should serialize required properties first
|
|
363
|
+
const propertiesKeys = Object.keys(schema.properties || {}).sort(
|
|
364
|
+
(key1, key2) => {
|
|
365
|
+
const required1 = requiredProperties.includes(key1)
|
|
366
|
+
const required2 = requiredProperties.includes(key2)
|
|
367
|
+
return required1 === required2 ? 0 : required1 ? -1 : 1
|
|
368
|
+
}
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
let code = ''
|
|
372
|
+
|
|
373
|
+
for (const key of requiredProperties) {
|
|
374
|
+
if (!propertiesKeys.includes(key)) {
|
|
375
|
+
const sanitizedKey = JSON.stringify(key)
|
|
376
|
+
code += `if (${objVar}[${sanitizedKey}] === undefined) throw new Error('${sanitizedKey.replace(/'/g, '\\\'')} is required!')\n`
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
code += 'json += JSON_STR_BEGIN_OBJECT\n'
|
|
381
|
+
|
|
382
|
+
const localUid = context.uid++
|
|
383
|
+
let addComma = ''
|
|
384
|
+
|
|
385
|
+
if (requiredProperties.length > 0) {
|
|
386
|
+
// If we have required properties, we know that at least one property will be serialized.
|
|
387
|
+
// We can avoid the runtime check for the comma.
|
|
388
|
+
|
|
389
|
+
// The first property is required, so we don't need a comma.
|
|
390
|
+
// For the subsequent properties, we can blindly add a comma.
|
|
391
|
+
|
|
392
|
+
for (let i = 0; i < propertiesKeys.length; i++) {
|
|
393
|
+
const key = propertiesKeys[i]
|
|
394
|
+
const propertyLocation = propertiesLocation.getPropertyLocation(key)
|
|
395
|
+
|
|
396
|
+
let resolvedLocation = propertyLocation
|
|
397
|
+
if (propertyLocation.schema.$ref) {
|
|
398
|
+
resolvedLocation = resolveRef(context, propertyLocation)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const sanitizedKey = JSON.stringify(key)
|
|
402
|
+
const value = `value_${key.replace(/[^a-zA-Z0-9]/g, '_')}_${context.uid++}`
|
|
403
|
+
const defaultValue = resolvedLocation.schema.default
|
|
404
|
+
const isRequired = requiredProperties.includes(key)
|
|
405
|
+
|
|
406
|
+
// i === 0 means it's the first property, and it IS required (due to sort). No comma.
|
|
407
|
+
// i > 0 means it follows a required property (or a sequence starting with one). Unconditional comma.
|
|
408
|
+
const currentAddComma = i === 0 ? '' : 'json += JSON_STR_COMMA'
|
|
409
|
+
|
|
410
|
+
code += `
|
|
411
|
+
const ${value} = ${objVar}[${sanitizedKey}]
|
|
412
|
+
if (${value} !== undefined) {
|
|
413
|
+
${currentAddComma}
|
|
414
|
+
json += ${JSON.stringify(sanitizedKey + ':')}
|
|
415
|
+
${buildValue(context, resolvedLocation, `${value}`)}
|
|
416
|
+
}`
|
|
417
|
+
|
|
418
|
+
if (defaultValue !== undefined) {
|
|
419
|
+
code += ` else {
|
|
420
|
+
${currentAddComma}
|
|
421
|
+
json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
|
|
422
|
+
}
|
|
423
|
+
`
|
|
424
|
+
} else if (isRequired) {
|
|
425
|
+
code += ` else {
|
|
426
|
+
throw new Error('${sanitizedKey.replace(/'/g, '\\\'')} is required!')
|
|
427
|
+
}
|
|
428
|
+
`
|
|
429
|
+
} else {
|
|
430
|
+
code += '\n'
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
addComma = 'json += JSON_STR_COMMA'
|
|
435
|
+
} else {
|
|
436
|
+
const needsRuntimeComma = propertiesKeys.length > 1 || schema.patternProperties || (schema.additionalProperties !== undefined && schema.additionalProperties !== false)
|
|
437
|
+
|
|
438
|
+
if (needsRuntimeComma) {
|
|
439
|
+
code += `let addComma_${localUid} = false\n`
|
|
440
|
+
addComma = `!addComma_${localUid} && (addComma_${localUid} = true) || (json += JSON_STR_COMMA)`
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
for (const key of propertiesKeys) {
|
|
444
|
+
let propertyLocation = propertiesLocation.getPropertyLocation(key)
|
|
445
|
+
if (propertyLocation.schema.$ref) {
|
|
446
|
+
propertyLocation = resolveRef(context, propertyLocation)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const sanitizedKey = JSON.stringify(key)
|
|
450
|
+
const value = `value_${key.replace(/[^a-zA-Z0-9]/g, '_')}_${context.uid++}`
|
|
451
|
+
const defaultValue = propertyLocation.schema.default
|
|
452
|
+
const isRequired = requiredProperties.includes(key) // Should be false here but good to keep
|
|
453
|
+
|
|
454
|
+
code += `
|
|
455
|
+
const ${value} = ${objVar}[${sanitizedKey}]
|
|
456
|
+
if (${value} !== undefined) {
|
|
457
|
+
${addComma}
|
|
458
|
+
json += ${JSON.stringify(sanitizedKey + ':')}
|
|
459
|
+
${buildValue(context, propertyLocation, `${value}`)}
|
|
460
|
+
}`
|
|
461
|
+
|
|
462
|
+
if (defaultValue !== undefined) {
|
|
463
|
+
code += ` else {
|
|
464
|
+
${addComma}
|
|
465
|
+
json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
|
|
466
|
+
}
|
|
467
|
+
`
|
|
468
|
+
} else if (isRequired) {
|
|
469
|
+
// Should not happen if requiredProperties.length === 0 but safety
|
|
470
|
+
code += ` else {
|
|
471
|
+
throw new Error('${sanitizedKey.replace(/'/g, '\\\'')} is required!')
|
|
472
|
+
}
|
|
473
|
+
`
|
|
474
|
+
} else {
|
|
475
|
+
code += '\n'
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (schema.patternProperties || schema.additionalProperties) {
|
|
481
|
+
code += buildExtraObjectPropertiesSerializer(context, location, addComma, objVar)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
code += `
|
|
485
|
+
json += JSON_STR_END_OBJECT
|
|
486
|
+
`
|
|
487
|
+
return code
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function mergeLocations (context, mergedSchemaId, mergedLocations) {
|
|
491
|
+
for (let i = 0, mergedLocationsLength = mergedLocations.length; i < mergedLocationsLength; i++) {
|
|
492
|
+
const location = mergedLocations[i]
|
|
493
|
+
const schema = location.schema
|
|
494
|
+
if (schema.$ref) {
|
|
495
|
+
mergedLocations[i] = resolveRef(context, location)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const mergedSchemas = []
|
|
500
|
+
for (const location of mergedLocations) {
|
|
501
|
+
const schema = cloneOriginSchema(context, location.schema, location.schemaId)
|
|
502
|
+
delete schema.$id
|
|
503
|
+
|
|
504
|
+
mergedSchemas.push(schema)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const mergedSchema = mergeSchemas(mergedSchemas)
|
|
508
|
+
const mergedLocation = new Location(mergedSchema, mergedSchemaId)
|
|
509
|
+
|
|
510
|
+
context.refResolver.addSchema(mergedSchema, mergedSchemaId)
|
|
511
|
+
return mergedLocation
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function cloneOriginSchema (context, schema, schemaId) {
|
|
515
|
+
const clonedSchema = Array.isArray(schema) ? [] : {}
|
|
516
|
+
|
|
517
|
+
if (
|
|
518
|
+
schema.$id !== undefined &&
|
|
519
|
+
schema.$id.charAt(0) !== '#'
|
|
520
|
+
) {
|
|
521
|
+
schemaId = schema.$id
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const mergedSchemaRef = context.mergedSchemasIds.get(schema)
|
|
525
|
+
if (mergedSchemaRef) {
|
|
526
|
+
context.mergedSchemasIds.set(clonedSchema, mergedSchemaRef)
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
for (const key in schema) {
|
|
530
|
+
let value = schema[key]
|
|
531
|
+
|
|
532
|
+
if (key === '$ref' && typeof value === 'string' && value.charAt(0) === '#') {
|
|
533
|
+
value = schemaId + value
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (typeof value === 'object' && value !== null) {
|
|
537
|
+
value = cloneOriginSchema(context, value, schemaId)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
clonedSchema[key] = value
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return clonedSchema
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function toJSON (variableName) {
|
|
547
|
+
return `(${variableName} && typeof ${variableName}.toJSON === 'function')
|
|
548
|
+
? ${variableName}.toJSON()
|
|
549
|
+
: ${variableName}
|
|
550
|
+
`
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function buildObject (context, location, input) {
|
|
554
|
+
const schema = location.schema
|
|
555
|
+
|
|
556
|
+
if (context.functionsNamesBySchema.has(schema)) {
|
|
557
|
+
const funcName = context.functionsNamesBySchema.get(schema)
|
|
558
|
+
return `json += ${funcName}(${input})`
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const nullable = schema.nullable === true
|
|
562
|
+
|
|
563
|
+
const schemaId = location.schemaId || ''
|
|
564
|
+
const jsonPointer = location.jsonPointer || ''
|
|
565
|
+
const fullPath = `${schemaId}#${jsonPointer}`
|
|
566
|
+
|
|
567
|
+
if (context.recursivePaths.has(fullPath) || context.buildingSet.has(schema) || schemaId !== '') {
|
|
568
|
+
const functionName = generateFuncName(context)
|
|
569
|
+
context.functionsNamesBySchema.set(schema, functionName)
|
|
570
|
+
|
|
571
|
+
const schemaRef = getSafeSchemaRef(context, location)
|
|
572
|
+
|
|
573
|
+
const functionCode = `
|
|
574
|
+
// ${schemaRef}
|
|
575
|
+
function ${functionName} (input) {
|
|
576
|
+
const obj = ${toJSON('input')}
|
|
577
|
+
if (obj === null) return ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_OBJECT'}
|
|
578
|
+
let json = ''
|
|
579
|
+
|
|
580
|
+
${buildInnerObject(context, location, 'obj')}
|
|
581
|
+
return json
|
|
582
|
+
}
|
|
583
|
+
`
|
|
584
|
+
|
|
585
|
+
context.functions.push(functionCode)
|
|
586
|
+
return `json += ${functionName}(${input})`
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
context.buildingSet.add(schema)
|
|
590
|
+
const objVar = `obj_${context.uid++}`
|
|
591
|
+
const code = `
|
|
592
|
+
const ${objVar} = ${toJSON(input)}
|
|
593
|
+
if (${objVar} === null) {
|
|
594
|
+
json += ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_OBJECT'}
|
|
595
|
+
} else {
|
|
596
|
+
${buildInnerObject(context, location, objVar)}
|
|
597
|
+
}
|
|
598
|
+
`
|
|
599
|
+
context.buildingSet.delete(schema)
|
|
600
|
+
return code
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function buildArray (context, location, input) {
|
|
604
|
+
const schema = location.schema
|
|
605
|
+
|
|
606
|
+
let itemsLocation = location.getPropertyLocation('items')
|
|
607
|
+
itemsLocation.schema = itemsLocation.schema || {}
|
|
608
|
+
|
|
609
|
+
if (itemsLocation.schema.$ref) {
|
|
610
|
+
itemsLocation = resolveRef(context, itemsLocation)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const itemsSchema = itemsLocation.schema
|
|
614
|
+
|
|
615
|
+
if (context.functionsNamesBySchema.has(schema)) {
|
|
616
|
+
const funcName = context.functionsNamesBySchema.get(schema)
|
|
617
|
+
return `json += ${funcName}(${input})`
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const nullable = schema.nullable === true
|
|
621
|
+
|
|
622
|
+
const schemaId = location.schemaId || ''
|
|
623
|
+
const jsonPointer = location.jsonPointer || ''
|
|
624
|
+
const fullPath = `${schemaId}#${jsonPointer}`
|
|
625
|
+
|
|
626
|
+
if (context.recursivePaths.has(fullPath) || context.buildingSet.has(schema) || schemaId !== '') {
|
|
627
|
+
const functionName = generateFuncName(context)
|
|
628
|
+
context.functionsNamesBySchema.set(schema, functionName)
|
|
629
|
+
|
|
630
|
+
const schemaRef = getSafeSchemaRef(context, location)
|
|
631
|
+
|
|
632
|
+
let functionCode = `
|
|
633
|
+
function ${functionName} (obj) {
|
|
634
|
+
// ${schemaRef}
|
|
635
|
+
let json = ''
|
|
636
|
+
`
|
|
637
|
+
|
|
638
|
+
functionCode += `
|
|
639
|
+
if (obj === null) return ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_ARRAY'}
|
|
640
|
+
if (!Array.isArray(obj)) {
|
|
641
|
+
throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
|
|
642
|
+
}
|
|
643
|
+
const arrayLength = obj.length
|
|
644
|
+
`
|
|
645
|
+
|
|
646
|
+
if (!schema.additionalItems && Array.isArray(itemsSchema)) {
|
|
647
|
+
functionCode += `
|
|
648
|
+
if (arrayLength > ${itemsSchema.length}) {
|
|
649
|
+
throw new Error(\`Item at ${itemsSchema.length} does not match schema definition.\`)
|
|
650
|
+
}
|
|
651
|
+
`
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (largeArrayMechanism === 'json-stringify') {
|
|
655
|
+
functionCode += `if (arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
functionCode += `
|
|
659
|
+
json += JSON_STR_BEGIN_ARRAY
|
|
660
|
+
`
|
|
661
|
+
|
|
662
|
+
if (Array.isArray(itemsSchema)) {
|
|
663
|
+
for (let i = 0, itemsSchemaLength = itemsSchema.length; i < itemsSchemaLength; i++) {
|
|
664
|
+
let item = itemsSchema[i]
|
|
665
|
+
let itemLocation = itemsLocation.getPropertyLocation(i)
|
|
666
|
+
if (itemLocation.schema.$ref) {
|
|
667
|
+
itemLocation = resolveRef(context, itemLocation)
|
|
668
|
+
item = itemLocation.schema
|
|
669
|
+
}
|
|
670
|
+
const value = `value_${i}`
|
|
671
|
+
functionCode += `const ${value} = obj[${i}]`
|
|
672
|
+
const tmpRes = buildValue(context, itemLocation, value)
|
|
673
|
+
functionCode += `
|
|
674
|
+
if (${i} < arrayLength) {
|
|
675
|
+
if (${buildArrayTypeCondition(item.type, value)}) {
|
|
676
|
+
if (${i}) {
|
|
677
|
+
json += JSON_STR_COMMA
|
|
678
|
+
}
|
|
679
|
+
${tmpRes}
|
|
680
|
+
} else {
|
|
681
|
+
throw new Error(\`Item at ${i} does not match schema definition.\`)
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
`
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (schema.additionalItems) {
|
|
688
|
+
functionCode += `
|
|
689
|
+
for (let i = ${itemsSchema.length}; i < arrayLength; i++) {
|
|
690
|
+
if (i) {
|
|
691
|
+
json += JSON_STR_COMMA
|
|
692
|
+
}
|
|
693
|
+
json += JSON.stringify(obj[i])
|
|
694
|
+
}`
|
|
695
|
+
}
|
|
696
|
+
} else {
|
|
697
|
+
const code = buildValue(context, itemsLocation, 'value')
|
|
698
|
+
functionCode += `
|
|
699
|
+
if (arrayLength > 0) {
|
|
700
|
+
const value = obj[0]
|
|
701
|
+
${code}
|
|
702
|
+
for (let i = 1; i < arrayLength; i++) {
|
|
703
|
+
json += JSON_STR_COMMA
|
|
704
|
+
const value = obj[i]
|
|
705
|
+
${code}
|
|
706
|
+
}
|
|
707
|
+
}`
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
functionCode += `
|
|
711
|
+
return json + JSON_STR_END_ARRAY
|
|
712
|
+
}`
|
|
713
|
+
|
|
714
|
+
context.functions.push(functionCode)
|
|
715
|
+
return `json += ${functionName}(${input})`
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
context.buildingSet.add(schema)
|
|
719
|
+
const safeSchemaRef = getSafeSchemaRef(context, location)
|
|
720
|
+
const objVar = `obj_${context.uid++}`
|
|
721
|
+
let inlinedCode = `
|
|
722
|
+
const ${objVar} = ${input}
|
|
723
|
+
if (${objVar} === null) {
|
|
724
|
+
json += ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_ARRAY'}
|
|
725
|
+
} else if (!Array.isArray(${objVar})) {
|
|
726
|
+
throw new TypeError(\`The value of '${safeSchemaRef}' does not match schema definition.\`)
|
|
727
|
+
} else {
|
|
728
|
+
const arrayLength_${objVar} = ${objVar}.length
|
|
729
|
+
`
|
|
730
|
+
|
|
731
|
+
if (!schema.additionalItems && Array.isArray(itemsSchema)) {
|
|
732
|
+
inlinedCode += `
|
|
733
|
+
if (arrayLength_${objVar} > ${itemsSchema.length}) {
|
|
734
|
+
throw new Error(\`Item at ${itemsSchema.length} does not match schema definition.\`)
|
|
735
|
+
}
|
|
736
|
+
`
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
if (largeArrayMechanism === 'json-stringify') {
|
|
740
|
+
inlinedCode += `if (arrayLength_${objVar} >= ${largeArraySize}) json += JSON.stringify(${objVar})\n else {`
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
inlinedCode += `
|
|
744
|
+
json += JSON_STR_BEGIN_ARRAY
|
|
745
|
+
`
|
|
746
|
+
|
|
747
|
+
if (Array.isArray(itemsSchema)) {
|
|
748
|
+
const localUid = context.uid++
|
|
749
|
+
inlinedCode += `let addComma_${localUid} = false\n`
|
|
750
|
+
for (let i = 0, itemsSchemaLength = itemsSchema.length; i < itemsSchemaLength; i++) {
|
|
751
|
+
let item = itemsSchema[i]
|
|
752
|
+
let itemLocation = itemsLocation.getPropertyLocation(i)
|
|
753
|
+
if (itemLocation.schema.$ref) {
|
|
754
|
+
itemLocation = resolveRef(context, itemLocation)
|
|
755
|
+
item = itemLocation.schema
|
|
756
|
+
}
|
|
757
|
+
const value = `value_${i}_${context.uid++}`
|
|
758
|
+
inlinedCode += `const ${value} = ${objVar}[${i}]`
|
|
759
|
+
const tmpRes = buildValue(context, itemLocation, value)
|
|
760
|
+
inlinedCode += `
|
|
761
|
+
if (${i} < arrayLength_${objVar}) {
|
|
762
|
+
if (${buildArrayTypeCondition(item.type, value)}) {
|
|
763
|
+
!addComma_${localUid} && (addComma_${localUid} = true) || (json += JSON_STR_COMMA)
|
|
764
|
+
${tmpRes}
|
|
765
|
+
} else {
|
|
766
|
+
throw new Error(\`Item at ${i} does not match schema definition.\`)
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
`
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (schema.additionalItems) {
|
|
773
|
+
inlinedCode += `
|
|
774
|
+
for (let i = ${itemsSchema.length}; i < arrayLength_${objVar}; i++) {
|
|
775
|
+
!addComma_${localUid} && (addComma_${localUid} = true) || (json += JSON_STR_COMMA)
|
|
776
|
+
json += JSON.stringify(${objVar}[i])
|
|
777
|
+
}`
|
|
778
|
+
}
|
|
779
|
+
} else {
|
|
780
|
+
const code = buildValue(context, itemsLocation, 'value')
|
|
781
|
+
inlinedCode += `
|
|
782
|
+
if (arrayLength_${objVar} > 0) {
|
|
783
|
+
const value = ${objVar}[0]
|
|
784
|
+
${code}
|
|
785
|
+
for (let i = 1; i < arrayLength_${objVar}; i++) {
|
|
786
|
+
json += JSON_STR_COMMA
|
|
787
|
+
const value = ${objVar}[i]
|
|
788
|
+
${code}
|
|
789
|
+
}
|
|
790
|
+
}`
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
inlinedCode += `
|
|
794
|
+
json += JSON_STR_END_ARRAY
|
|
795
|
+
`
|
|
796
|
+
|
|
797
|
+
if (largeArrayMechanism === 'json-stringify') {
|
|
798
|
+
inlinedCode += '}'
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
inlinedCode += '}'
|
|
802
|
+
context.buildingSet.delete(schema)
|
|
803
|
+
return inlinedCode
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function buildArrayTypeCondition (type, accessor) {
|
|
807
|
+
let condition
|
|
808
|
+
switch (type) {
|
|
809
|
+
case 'null':
|
|
810
|
+
condition = `${accessor} === null`
|
|
811
|
+
break
|
|
812
|
+
case 'string':
|
|
813
|
+
condition = `typeof ${accessor} === 'string' ||
|
|
814
|
+
${accessor} === null ||
|
|
815
|
+
${accessor} instanceof Date ||
|
|
816
|
+
${accessor} instanceof RegExp ||
|
|
817
|
+
(
|
|
818
|
+
typeof ${accessor} === "object" &&
|
|
819
|
+
typeof ${accessor}.toString === "function" &&
|
|
820
|
+
${accessor}.toString !== Object.prototype.toString
|
|
821
|
+
)`
|
|
822
|
+
break
|
|
823
|
+
case 'integer':
|
|
824
|
+
condition = `Number.isInteger(${accessor})`
|
|
825
|
+
break
|
|
826
|
+
case 'number':
|
|
827
|
+
condition = `Number.isFinite(${accessor})`
|
|
828
|
+
break
|
|
829
|
+
case 'boolean':
|
|
830
|
+
condition = `typeof ${accessor} === 'boolean'`
|
|
831
|
+
break
|
|
832
|
+
case 'object':
|
|
833
|
+
condition = `${accessor} && typeof ${accessor} === 'object' && ${accessor}.constructor === Object`
|
|
834
|
+
break
|
|
835
|
+
case 'array':
|
|
836
|
+
condition = `Array.isArray(${accessor})`
|
|
837
|
+
break
|
|
838
|
+
default:
|
|
839
|
+
if (Array.isArray(type)) {
|
|
840
|
+
const conditions = type.map((subType) => {
|
|
841
|
+
return buildArrayTypeCondition(subType, accessor)
|
|
842
|
+
})
|
|
843
|
+
condition = `(${conditions.join(' || ')})`
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return condition
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function generateFuncName (context) {
|
|
850
|
+
return 'anonymous' + context.functionsCounter++
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function buildMultiTypeSerializer (context, location, input) {
|
|
854
|
+
const schema = location.schema
|
|
855
|
+
const types = schema.type.sort(t1 => t1 === 'null' ? -1 : 1)
|
|
856
|
+
|
|
857
|
+
let code = ''
|
|
858
|
+
|
|
859
|
+
types.forEach((type, index) => {
|
|
860
|
+
location.schema = { ...location.schema, type }
|
|
861
|
+
const nestedResult = buildSingleTypeSerializer(context, location, input)
|
|
862
|
+
|
|
863
|
+
const statement = index === 0 ? 'if' : 'else if'
|
|
864
|
+
switch (type) {
|
|
865
|
+
case 'null':
|
|
866
|
+
code += `
|
|
867
|
+
${statement} (${input} === null) {
|
|
868
|
+
${nestedResult}
|
|
869
|
+
}
|
|
870
|
+
`
|
|
871
|
+
break
|
|
872
|
+
case 'string': {
|
|
873
|
+
code += `
|
|
874
|
+
${statement}(
|
|
875
|
+
typeof ${input} === "string" ||
|
|
876
|
+
${input} === null ||
|
|
877
|
+
${input} instanceof Date ||
|
|
878
|
+
${input} instanceof RegExp ||
|
|
879
|
+
(
|
|
880
|
+
typeof ${input} === "object" &&
|
|
881
|
+
typeof ${input}.toString === "function" &&
|
|
882
|
+
${input}.toString !== Object.prototype.toString
|
|
883
|
+
)
|
|
884
|
+
) {
|
|
885
|
+
${nestedResult}
|
|
886
|
+
}
|
|
887
|
+
`
|
|
888
|
+
break
|
|
889
|
+
}
|
|
890
|
+
case 'array': {
|
|
891
|
+
code += `
|
|
892
|
+
${statement}(Array.isArray(${input})) {
|
|
893
|
+
${nestedResult}
|
|
894
|
+
}
|
|
895
|
+
`
|
|
896
|
+
break
|
|
897
|
+
}
|
|
898
|
+
case 'integer': {
|
|
899
|
+
code += `
|
|
900
|
+
${statement}(Number.isInteger(${input}) || ${input} === null) {
|
|
901
|
+
${nestedResult}
|
|
902
|
+
}
|
|
903
|
+
`
|
|
904
|
+
break
|
|
905
|
+
}
|
|
906
|
+
default: {
|
|
907
|
+
code += `
|
|
908
|
+
${statement}(typeof ${input} === "${type}" || ${input} === null) {
|
|
909
|
+
${nestedResult}
|
|
910
|
+
}
|
|
911
|
+
`
|
|
912
|
+
break
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
})
|
|
916
|
+
code += `
|
|
917
|
+
else throw new TypeError(\`The value of '${getSafeSchemaRef(context, location)}' does not match schema definition.\`)
|
|
918
|
+
`
|
|
919
|
+
|
|
920
|
+
return code
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function buildSingleTypeSerializer (context, location, input) {
|
|
924
|
+
const schema = location.schema
|
|
925
|
+
|
|
926
|
+
switch (schema.type) {
|
|
927
|
+
case 'null':
|
|
928
|
+
return 'json += JSON_STR_NULL'
|
|
929
|
+
case 'string': {
|
|
930
|
+
if (schema.format === 'date-time') {
|
|
931
|
+
return `json += asDateTime(${input})`
|
|
932
|
+
} else if (schema.format === 'date') {
|
|
933
|
+
return `json += asDate(${input})`
|
|
934
|
+
} else if (schema.format === 'time') {
|
|
935
|
+
return `json += asTime(${input})`
|
|
936
|
+
} else if (schema.format === 'unsafe') {
|
|
937
|
+
return `json += asUnsafeString(${input})`
|
|
938
|
+
} else {
|
|
939
|
+
return `
|
|
940
|
+
if (typeof ${input} !== 'string') {
|
|
941
|
+
if (${input} === null) {
|
|
942
|
+
json += JSON_STR_EMPTY_STRING
|
|
943
|
+
} else if (${input} instanceof Date) {
|
|
944
|
+
json += JSON_STR_QUOTE + ${input}.toISOString() + JSON_STR_QUOTE
|
|
945
|
+
} else if (${input} instanceof RegExp) {
|
|
946
|
+
json += asString(${input}.source)
|
|
947
|
+
} else {
|
|
948
|
+
json += asString(${input}.toString())
|
|
949
|
+
}
|
|
950
|
+
} else {
|
|
951
|
+
json += asString(${input})
|
|
952
|
+
}
|
|
953
|
+
`
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
case 'integer':
|
|
957
|
+
return `json += asInteger(${input})`
|
|
958
|
+
case 'number':
|
|
959
|
+
return `json += asNumber(${input})`
|
|
960
|
+
case 'boolean':
|
|
961
|
+
return `json += asBoolean(${input})`
|
|
962
|
+
case 'object': {
|
|
963
|
+
return buildObject(context, location, input)
|
|
964
|
+
}
|
|
965
|
+
case 'array': {
|
|
966
|
+
return buildArray(context, location, input)
|
|
967
|
+
}
|
|
968
|
+
case undefined:
|
|
969
|
+
return `json += JSON.stringify(${input})`
|
|
970
|
+
default:
|
|
971
|
+
throw new Error(`${schema.type} unsupported`)
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
function detectRecursiveSchemas (context, location) {
|
|
976
|
+
const pathStack = new Set()
|
|
977
|
+
function traverse (location) {
|
|
978
|
+
const schema = location.schema
|
|
979
|
+
if (typeof schema !== 'object' || schema === null) return
|
|
980
|
+
|
|
981
|
+
const schemaId = location.schemaId || ''
|
|
982
|
+
const jsonPointer = location.jsonPointer || ''
|
|
983
|
+
const fullPath = `${schemaId}#${jsonPointer}`
|
|
984
|
+
|
|
985
|
+
if (pathStack.has(fullPath)) {
|
|
986
|
+
// Mark all nodes in the current path that are part of the cycle
|
|
987
|
+
let inCycle = false
|
|
988
|
+
for (const p of pathStack) {
|
|
989
|
+
if (p === fullPath) inCycle = true
|
|
990
|
+
if (inCycle) context.recursivePaths.add(p)
|
|
991
|
+
}
|
|
992
|
+
context.recursivePaths.add(fullPath)
|
|
993
|
+
return
|
|
994
|
+
}
|
|
995
|
+
pathStack.add(fullPath)
|
|
996
|
+
|
|
997
|
+
if (schema.$ref) {
|
|
998
|
+
try {
|
|
999
|
+
const res = resolveRef(context, location)
|
|
1000
|
+
traverse(res)
|
|
1001
|
+
} catch (err) {
|
|
1002
|
+
// Validation will handle missing refs later
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (schema.properties) {
|
|
1007
|
+
const propertiesLocation = location.getPropertyLocation('properties')
|
|
1008
|
+
for (const key in schema.properties) {
|
|
1009
|
+
traverse(propertiesLocation.getPropertyLocation(key))
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
|
|
1013
|
+
traverse(location.getPropertyLocation('additionalProperties'))
|
|
1014
|
+
}
|
|
1015
|
+
if (schema.patternProperties) {
|
|
1016
|
+
const patternPropertiesLocation = location.getPropertyLocation('patternProperties')
|
|
1017
|
+
for (const key in schema.patternProperties) {
|
|
1018
|
+
traverse(patternPropertiesLocation.getPropertyLocation(key))
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
if (schema.items) {
|
|
1022
|
+
const itemsLocation = location.getPropertyLocation('items')
|
|
1023
|
+
if (Array.isArray(schema.items)) {
|
|
1024
|
+
for (let i = 0; i < schema.items.length; i++) {
|
|
1025
|
+
traverse(itemsLocation.getPropertyLocation(i))
|
|
1026
|
+
}
|
|
1027
|
+
} else {
|
|
1028
|
+
traverse(itemsLocation)
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (schema.additionalItems && typeof schema.additionalItems === 'object') {
|
|
1032
|
+
traverse(location.getPropertyLocation('additionalItems'))
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if (schema.oneOf) {
|
|
1036
|
+
const oneOfLocation = location.getPropertyLocation('oneOf')
|
|
1037
|
+
for (let i = 0; i < schema.oneOf.length; i++) {
|
|
1038
|
+
traverse(oneOfLocation.getPropertyLocation(i))
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
if (schema.anyOf) {
|
|
1042
|
+
const anyOfLocation = location.getPropertyLocation('anyOf')
|
|
1043
|
+
for (let i = 0; i < schema.anyOf.length; i++) {
|
|
1044
|
+
traverse(anyOfLocation.getPropertyLocation(i))
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (schema.allOf) {
|
|
1048
|
+
const allOfLocation = location.getPropertyLocation('allOf')
|
|
1049
|
+
for (let i = 0; i < schema.allOf.length; i++) {
|
|
1050
|
+
traverse(allOfLocation.getPropertyLocation(i))
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (schema.then) traverse(location.getPropertyLocation('then'))
|
|
1054
|
+
if (schema.else) traverse(location.getPropertyLocation('else'))
|
|
1055
|
+
|
|
1056
|
+
pathStack.delete(fullPath)
|
|
1057
|
+
}
|
|
1058
|
+
traverse(location)
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
function buildConstSerializer (location, input) {
|
|
1062
|
+
const schema = location.schema
|
|
1063
|
+
const type = schema.type
|
|
1064
|
+
|
|
1065
|
+
const hasNullType = Array.isArray(type) && type.includes('null')
|
|
1066
|
+
|
|
1067
|
+
let code = ''
|
|
1068
|
+
|
|
1069
|
+
if (hasNullType) {
|
|
1070
|
+
code += `
|
|
1071
|
+
if (${input} === null) {
|
|
1072
|
+
json += JSON_STR_NULL
|
|
1073
|
+
} else {
|
|
1074
|
+
`
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
code += `json += '${JSON.stringify(schema.const).replace(SINGLE_TICK, "\\'")}'`
|
|
1078
|
+
|
|
1079
|
+
if (hasNullType) {
|
|
1080
|
+
code += `
|
|
1081
|
+
}
|
|
1082
|
+
`
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
return code
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
function buildAllOf (context, location, input) {
|
|
1089
|
+
const schema = location.schema
|
|
1090
|
+
|
|
1091
|
+
let mergedSchemaId = context.mergedSchemasIds.get(schema)
|
|
1092
|
+
if (mergedSchemaId) {
|
|
1093
|
+
const mergedLocation = getMergedLocation(context, mergedSchemaId)
|
|
1094
|
+
return buildValue(context, mergedLocation, input)
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
1098
|
+
context.mergedSchemasIds.set(schema, mergedSchemaId)
|
|
1099
|
+
|
|
1100
|
+
const { allOf, ...schemaWithoutAllOf } = location.schema
|
|
1101
|
+
const locations = [
|
|
1102
|
+
new Location(
|
|
1103
|
+
schemaWithoutAllOf,
|
|
1104
|
+
location.schemaId,
|
|
1105
|
+
location.jsonPointer
|
|
1106
|
+
)
|
|
1107
|
+
]
|
|
1108
|
+
|
|
1109
|
+
const allOfsLocation = location.getPropertyLocation('allOf')
|
|
1110
|
+
for (let i = 0, allOfLength = allOf.length; i < allOfLength; i++) {
|
|
1111
|
+
locations.push(allOfsLocation.getPropertyLocation(i))
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
const mergedLocation = mergeLocations(context, mergedSchemaId, locations)
|
|
1115
|
+
return buildValue(context, mergedLocation, input)
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
function buildOneOf (context, location, input) {
|
|
1119
|
+
context.validatorSchemasIds.add(location.schemaId)
|
|
1120
|
+
|
|
1121
|
+
const schema = location.schema
|
|
1122
|
+
|
|
1123
|
+
const type = schema.anyOf ? 'anyOf' : 'oneOf'
|
|
1124
|
+
const { [type]: oneOfs, ...schemaWithoutAnyOf } = location.schema
|
|
1125
|
+
|
|
1126
|
+
const locationWithoutOneOf = new Location(
|
|
1127
|
+
schemaWithoutAnyOf,
|
|
1128
|
+
location.schemaId,
|
|
1129
|
+
location.jsonPointer
|
|
1130
|
+
)
|
|
1131
|
+
const oneOfsLocation = location.getPropertyLocation(type)
|
|
1132
|
+
|
|
1133
|
+
let code = ''
|
|
1134
|
+
|
|
1135
|
+
for (let index = 0, oneOfsLength = oneOfs.length; index < oneOfsLength; index++) {
|
|
1136
|
+
const optionLocation = oneOfsLocation.getPropertyLocation(index)
|
|
1137
|
+
const optionSchema = optionLocation.schema
|
|
1138
|
+
|
|
1139
|
+
let mergedSchemaId = context.mergedSchemasIds.get(optionSchema)
|
|
1140
|
+
let mergedLocation = null
|
|
1141
|
+
if (mergedSchemaId) {
|
|
1142
|
+
mergedLocation = getMergedLocation(context, mergedSchemaId)
|
|
1143
|
+
} else {
|
|
1144
|
+
mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
1145
|
+
context.mergedSchemasIds.set(optionSchema, mergedSchemaId)
|
|
1146
|
+
|
|
1147
|
+
mergedLocation = mergeLocations(context, mergedSchemaId, [
|
|
1148
|
+
locationWithoutOneOf,
|
|
1149
|
+
optionLocation
|
|
1150
|
+
])
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const nestedResult = buildValue(context, mergedLocation, input)
|
|
1154
|
+
const schemaRef = optionLocation.getSchemaRef()
|
|
1155
|
+
|
|
1156
|
+
code += `
|
|
1157
|
+
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input})) {
|
|
1158
|
+
${nestedResult}
|
|
1159
|
+
}
|
|
1160
|
+
`
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
code += `
|
|
1164
|
+
else throw new TypeError(\`The value of '${getSafeSchemaRef(context, location)}' does not match schema definition.\`)
|
|
1165
|
+
`
|
|
1166
|
+
|
|
1167
|
+
return code
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
function buildIfThenElse (context, location, input) {
|
|
1171
|
+
context.validatorSchemasIds.add(location.schemaId)
|
|
1172
|
+
|
|
1173
|
+
const {
|
|
1174
|
+
if: ifSchema,
|
|
1175
|
+
then: thenSchema,
|
|
1176
|
+
else: elseSchema,
|
|
1177
|
+
...schemaWithoutIfThenElse
|
|
1178
|
+
} = location.schema
|
|
1179
|
+
|
|
1180
|
+
const rootLocation = new Location(
|
|
1181
|
+
schemaWithoutIfThenElse,
|
|
1182
|
+
location.schemaId,
|
|
1183
|
+
location.jsonPointer
|
|
1184
|
+
)
|
|
1185
|
+
|
|
1186
|
+
const ifLocation = location.getPropertyLocation('if')
|
|
1187
|
+
const ifSchemaRef = ifLocation.getSchemaRef()
|
|
1188
|
+
|
|
1189
|
+
const thenLocation = location.getPropertyLocation('then')
|
|
1190
|
+
let thenMergedSchemaId = context.mergedSchemasIds.get(thenSchema)
|
|
1191
|
+
let thenMergedLocation = null
|
|
1192
|
+
if (thenMergedSchemaId) {
|
|
1193
|
+
thenMergedLocation = getMergedLocation(context, thenMergedSchemaId)
|
|
1194
|
+
} else {
|
|
1195
|
+
thenMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
1196
|
+
context.mergedSchemasIds.set(thenSchema, thenMergedSchemaId)
|
|
1197
|
+
|
|
1198
|
+
thenMergedLocation = mergeLocations(context, thenMergedSchemaId, [
|
|
1199
|
+
rootLocation,
|
|
1200
|
+
thenLocation
|
|
1201
|
+
])
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
if (!elseSchema) {
|
|
1205
|
+
return `
|
|
1206
|
+
if (validator.validate("${ifSchemaRef}", ${input})) {
|
|
1207
|
+
${buildValue(context, thenMergedLocation, input)}
|
|
1208
|
+
} else {
|
|
1209
|
+
${buildValue(context, rootLocation, input)}
|
|
1210
|
+
}
|
|
1211
|
+
`
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
const elseLocation = location.getPropertyLocation('else')
|
|
1215
|
+
let elseMergedSchemaId = context.mergedSchemasIds.get(elseSchema)
|
|
1216
|
+
let elseMergedLocation = null
|
|
1217
|
+
if (elseMergedSchemaId) {
|
|
1218
|
+
elseMergedLocation = getMergedLocation(context, elseMergedSchemaId)
|
|
1219
|
+
} else {
|
|
1220
|
+
elseMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
1221
|
+
context.mergedSchemasIds.set(elseSchema, elseMergedSchemaId)
|
|
1222
|
+
|
|
1223
|
+
elseMergedLocation = mergeLocations(context, elseMergedSchemaId, [
|
|
1224
|
+
rootLocation,
|
|
1225
|
+
elseLocation
|
|
1226
|
+
])
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
return `
|
|
1230
|
+
if (validator.validate("${ifSchemaRef}", ${input})) {
|
|
1231
|
+
${buildValue(context, thenMergedLocation, input)}
|
|
1232
|
+
} else {
|
|
1233
|
+
${buildValue(context, elseMergedLocation, input)}
|
|
1234
|
+
}
|
|
1235
|
+
`
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
function buildValue (context, location, input) {
|
|
1239
|
+
let schema = location.schema
|
|
1240
|
+
|
|
1241
|
+
if (typeof schema === 'boolean') {
|
|
1242
|
+
return `json += JSON.stringify(${input})`
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
if (schema.$ref) {
|
|
1246
|
+
location = resolveRef(context, location)
|
|
1247
|
+
schema = location.schema
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
if (schema.allOf) {
|
|
1251
|
+
return buildAllOf(context, location, input)
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (schema.anyOf || schema.oneOf) {
|
|
1255
|
+
return buildOneOf(context, location, input)
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if (schema.if && schema.then) {
|
|
1259
|
+
return buildIfThenElse(context, location, input)
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
if (schema.type === undefined) {
|
|
1263
|
+
const inferredType = inferTypeByKeyword(schema)
|
|
1264
|
+
if (inferredType) {
|
|
1265
|
+
schema.type = inferredType
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
let code = ''
|
|
1270
|
+
|
|
1271
|
+
const type = schema.type
|
|
1272
|
+
const nullable = schema.nullable === true
|
|
1273
|
+
if (nullable) {
|
|
1274
|
+
code += `
|
|
1275
|
+
if (${input} === null) {
|
|
1276
|
+
json += JSON_STR_NULL
|
|
1277
|
+
} else {
|
|
1278
|
+
`
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
if (schema.const !== undefined) {
|
|
1282
|
+
code += buildConstSerializer(location, input)
|
|
1283
|
+
} else if (Array.isArray(type)) {
|
|
1284
|
+
code += buildMultiTypeSerializer(context, location, input)
|
|
1285
|
+
} else {
|
|
1286
|
+
code += buildSingleTypeSerializer(context, location, input)
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
if (nullable) {
|
|
1290
|
+
code += `
|
|
1291
|
+
}
|
|
1292
|
+
`
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
return code
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
module.exports = build
|
|
1299
|
+
module.exports.default = build
|
|
1300
|
+
module.exports.build = build
|
|
1301
|
+
|
|
1302
|
+
module.exports.validLargeArrayMechanisms = validLargeArrayMechanisms
|
|
1303
|
+
|
|
1304
|
+
module.exports.restore = function ({ code, validator, serializer }) {
|
|
1305
|
+
// eslint-disable-next-line
|
|
1306
|
+
return (Function.apply(null, ['validator', 'serializer', code])
|
|
1307
|
+
.apply(null, [validator, serializer]))
|
|
1308
|
+
}
|