@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.
Files changed (128) hide show
  1. package/node_modules/@fastify/fast-json-stringify-compiler/.github/dependabot.yml +42 -2
  2. package/node_modules/@fastify/fast-json-stringify-compiler/.github/workflows/ci.yml +6 -1
  3. package/node_modules/@fastify/fast-json-stringify-compiler/.github/workflows/lock-threads.yml +19 -0
  4. package/node_modules/@fastify/fast-json-stringify-compiler/LICENSE +1 -1
  5. package/node_modules/@fastify/fast-json-stringify-compiler/README.md +1 -1
  6. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.gitattributes +2 -0
  7. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.github/dependabot.yml +13 -0
  8. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.github/workflows/ci.yml +33 -0
  9. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/.github/workflows/lock-threads.yml +19 -0
  10. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/LICENSE +22 -0
  11. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/README.md +742 -0
  12. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench-cmp-branch.js +116 -0
  13. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench-cmp-lib.js +339 -0
  14. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench-thread.js +33 -0
  15. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/benchmark/bench.js +391 -0
  16. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/build/build-schema-validator.js +26 -0
  17. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/eslint.config.js +9 -0
  18. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/examples/example.js +81 -0
  19. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/examples/server.js +42 -0
  20. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/index.js +1308 -0
  21. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/location.js +24 -0
  22. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/merge-schemas.js +9 -0
  23. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/schema-validator.js +1134 -0
  24. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/serializer.js +141 -0
  25. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/standalone.js +34 -0
  26. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/lib/validator.js +96 -0
  27. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/package.json +89 -0
  28. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/additionalProperties.test.js +332 -0
  29. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/allof.test.js +751 -0
  30. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/any.test.js +231 -0
  31. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/anyof.test.js +812 -0
  32. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/array.test.js +688 -0
  33. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/asNumber.test.js +13 -0
  34. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/basic.test.js +400 -0
  35. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/bigint.test.js +76 -0
  36. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/clean-cache.test.js +47 -0
  37. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/const.test.js +314 -0
  38. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/date.test.js +639 -0
  39. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/debug-mode.test.js +130 -0
  40. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/defaults.test.js +376 -0
  41. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/enum.test.js +37 -0
  42. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/fix-604.test.js +25 -0
  43. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/fixtures/.keep +0 -0
  44. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/if-then-else.test.js +540 -0
  45. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/inferType.test.js +92 -0
  46. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/infinity.test.js +55 -0
  47. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/integer.test.js +194 -0
  48. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/invalidSchema.test.js +38 -0
  49. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-479.test.js +57 -0
  50. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-793.test.js +107 -0
  51. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-794.test.js +177 -0
  52. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/issue-836.test.js +183 -0
  53. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-add-comma.test.js +57 -0
  54. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/README.md +10 -0
  55. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft4/required.json +54 -0
  56. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft4.test.js +12 -0
  57. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft6/required.json +70 -0
  58. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft6.test.js +12 -0
  59. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft7/required.json +70 -0
  60. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/draft7.test.js +12 -0
  61. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/json-schema-test-suite/util.js +31 -0
  62. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/missing-values.test.js +88 -0
  63. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/multi-type-serializer.test.js +19 -0
  64. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/nestedObjects.test.js +63 -0
  65. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/nullable.test.js +543 -0
  66. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/oneof.test.js +510 -0
  67. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/patternProperties.test.js +168 -0
  68. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/recursion.test.js +245 -0
  69. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/ref.json +12 -0
  70. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/ref.test.js +2077 -0
  71. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/regex.test.js +32 -0
  72. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/required.test.js +204 -0
  73. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/requiresAjv.test.js +50 -0
  74. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize.test.js +141 -0
  75. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize2.test.js +18 -0
  76. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize3.test.js +17 -0
  77. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize4.test.js +16 -0
  78. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize5.test.js +16 -0
  79. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize6.test.js +22 -0
  80. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/sanitize7.test.js +68 -0
  81. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/side-effect.test.js +196 -0
  82. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/standalone-mode.test.js +219 -0
  83. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/string.test.js +84 -0
  84. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/surrogate.test.js +67 -0
  85. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/toJSON.test.js +203 -0
  86. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/typebox.test.js +36 -0
  87. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/typesArray.test.js +550 -0
  88. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/unknownFormats.test.js +27 -0
  89. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/test/webpack.test.js +50 -0
  90. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/types/index.d.ts +219 -0
  91. package/node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify/types/index.tst.ts +259 -0
  92. package/node_modules/@fastify/fast-json-stringify-compiler/package.json +6 -11
  93. package/node_modules/@fastify/fast-json-stringify-compiler/types/{index.test-d.ts → index.tst.ts} +34 -32
  94. package/node_modules/@protobufjs/utf8/CHANGELOG.md +8 -0
  95. package/node_modules/@protobufjs/utf8/index.js +29 -18
  96. package/node_modules/@protobufjs/utf8/package.json +2 -2
  97. package/node_modules/@protobufjs/utf8/tests/index.js +5 -0
  98. package/node_modules/@zuplo/core/package.json +1 -1
  99. package/node_modules/@zuplo/graphql/package.json +1 -1
  100. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  101. package/node_modules/@zuplo/otel/package.json +1 -1
  102. package/node_modules/@zuplo/runtime/out/esm/{chunk-5CYWMN74.js → chunk-D3O7C43P.js} +98 -97
  103. package/node_modules/@zuplo/runtime/out/esm/chunk-D3O7C43P.js.map +1 -0
  104. package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
  105. package/node_modules/@zuplo/runtime/out/esm/index.js.map +1 -1
  106. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
  107. package/node_modules/@zuplo/runtime/out/types/index.d.ts +172 -0
  108. package/node_modules/@zuplo/runtime/package.json +1 -1
  109. package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -1
  110. package/node_modules/hono/dist/adapter/bun/websocket.js +3 -1
  111. package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -1
  112. package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +3 -1
  113. package/node_modules/hono/dist/cjs/middleware/serve-static/index.js +1 -1
  114. package/node_modules/hono/dist/cjs/utils/body.js +12 -4
  115. package/node_modules/hono/dist/cjs/utils/buffer.js +2 -1
  116. package/node_modules/hono/dist/cjs/validator/validator.js +3 -3
  117. package/node_modules/hono/dist/middleware/serve-static/index.js +1 -1
  118. package/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +2 -2
  119. package/node_modules/hono/dist/types/utils/body.d.ts +1 -1
  120. package/node_modules/hono/dist/utils/body.js +12 -4
  121. package/node_modules/hono/dist/utils/buffer.js +2 -1
  122. package/node_modules/hono/dist/validator/validator.js +3 -3
  123. package/node_modules/hono/package.json +8 -7
  124. package/package.json +6 -6
  125. package/node_modules/@fastify/fast-json-stringify-compiler/.eslintrc +0 -1
  126. package/node_modules/@zuplo/runtime/out/esm/chunk-5CYWMN74.js.map +0 -1
  127. package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +0 -1
  128. /package/node_modules/@zuplo/runtime/out/esm/{chunk-5CYWMN74.js.LEGAL.txt → chunk-D3O7C43P.js.LEGAL.txt} +0 -0
@@ -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
+ }