fast-json-stringify 2.7.11 → 3.0.1
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/.github/dependabot.yml +4 -0
- package/.github/workflows/ci.yml +8 -4
- package/README.md +37 -63
- package/bench.js +44 -0
- package/build-schema-validator.js +14 -9
- package/index.js +92 -68
- package/package.json +3 -4
- package/schema-validator.js +1132 -1748
- package/test/allof.test.js +53 -1
- package/test/bigint.test.js +76 -0
- package/test/debug-mode.test.js +26 -0
- package/test/if-then-else.test.js +16 -1
- package/test/integer.test.js +1 -10
- package/test/nullable.test.js +9 -4
- package/test/recursion.test.js +43 -0
- package/test/side-effect.test.js +39 -0
- package/test/types/tsconfig.json +3 -1
- package/test/typesArray.test.js +2 -2
- package/test/bigint.js +0 -74
- package/test/long.test.js +0 -85
package/.github/dependabot.yml
CHANGED
|
@@ -2,6 +2,10 @@ version: 2
|
|
|
2
2
|
updates:
|
|
3
3
|
- package-ecosystem: github-actions
|
|
4
4
|
directory: '/'
|
|
5
|
+
ignore:
|
|
6
|
+
- dependency-name: "actions/*"
|
|
7
|
+
update-types:
|
|
8
|
+
["version-update:semver-minor", "version-update:semver-patch"]
|
|
5
9
|
schedule:
|
|
6
10
|
interval: daily
|
|
7
11
|
open-pull-requests-limit: 10
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -15,14 +15,14 @@ jobs:
|
|
|
15
15
|
runs-on: ${{ matrix.os }}
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
node-version: [
|
|
18
|
+
node-version: [14, 16, 17]
|
|
19
19
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
|
-
- uses: actions/checkout@v2
|
|
22
|
+
- uses: actions/checkout@v2
|
|
23
23
|
|
|
24
24
|
- name: Use Node.js
|
|
25
|
-
uses: actions/setup-node@v2
|
|
25
|
+
uses: actions/setup-node@v2
|
|
26
26
|
with:
|
|
27
27
|
node-version: ${{ matrix.node-version }}
|
|
28
28
|
|
|
@@ -37,7 +37,11 @@ jobs:
|
|
|
37
37
|
automerge:
|
|
38
38
|
needs: test
|
|
39
39
|
runs-on: ubuntu-latest
|
|
40
|
+
permissions:
|
|
41
|
+
pull-requests: write
|
|
42
|
+
contents: write
|
|
40
43
|
steps:
|
|
41
|
-
- uses: fastify/github-action-merge-dependabot@
|
|
44
|
+
- uses: fastify/github-action-merge-dependabot@v3
|
|
42
45
|
with:
|
|
43
46
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
47
|
+
target: minor
|
package/README.md
CHANGED
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/fast-json-stringify)
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads.
|
|
10
|
+
__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads.
|
|
11
|
+
Its performance advantage shrinks as your payload grows.
|
|
12
|
+
It pairs well with [__flatstr__](https://www.npmjs.com/package/flatstr), which triggers a V8 optimization that improves performance when eventually converting the string to a `Buffer`.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### How it works
|
|
16
|
+
|
|
17
|
+
fast-json-stringify requires a [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7) input to generate a fast `stringify` function.
|
|
11
18
|
|
|
12
19
|
##### Benchmarks
|
|
13
20
|
|
|
@@ -15,22 +22,28 @@ __fast-json-stringify__ is significantly faster than `JSON.stringify()` for smal
|
|
|
15
22
|
- Node.js `v16.9.1`
|
|
16
23
|
|
|
17
24
|
```
|
|
18
|
-
FJS creation x
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
JSON.stringify
|
|
30
|
-
fast-json-stringify
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
FJS creation x 8,443 ops/sec ±1.01% (90 runs sampled)
|
|
26
|
+
CJS creation x 183,219 ops/sec ±0.13% (96 runs sampled)
|
|
27
|
+
AJV Serialize creation x 83,541,848 ops/sec ±0.24% (98 runs sampled)
|
|
28
|
+
JSON.stringify array x 5,363 ops/sec ±0.11% (100 runs sampled)
|
|
29
|
+
fast-json-stringify array x 6,747 ops/sec ±0.13% (98 runs sampled)
|
|
30
|
+
compile-json-stringify array x 7,121 ops/sec ±0.42% (98 runs sampled)
|
|
31
|
+
AJV Serialize array x 7,533 ops/sec ±0.13% (98 runs sampled)
|
|
32
|
+
JSON.stringify long string x 16,461 ops/sec ±0.12% (98 runs sampled)
|
|
33
|
+
fast-json-stringify long string x 16,443 ops/sec ±0.37% (99 runs sampled)
|
|
34
|
+
compile-json-stringify long string x 16,458 ops/sec ±0.09% (98 runs sampled)
|
|
35
|
+
AJV Serialize long string x 21,433 ops/sec ±0.08% (95 runs sampled)
|
|
36
|
+
JSON.stringify short string x 12,035,664 ops/sec ±0.62% (96 runs sampled)
|
|
37
|
+
fast-json-stringify short string x 38,281,060 ops/sec ±0.24% (98 runs sampled)
|
|
38
|
+
compile-json-stringify short string x 32,388,037 ops/sec ±0.27% (97 runs sampled)
|
|
39
|
+
AJV Serialize short string x 32,288,612 ops/sec ±0.32% (95 runs sampled)
|
|
40
|
+
JSON.stringify obj x 3,068,185 ops/sec ±0.16% (98 runs sampled)
|
|
41
|
+
fast-json-stringify obj x 10,082,694 ops/sec ±0.10% (97 runs sampled)
|
|
42
|
+
compile-json-stringify obj x 17,037,963 ops/sec ±1.17% (97 runs sampled)
|
|
43
|
+
AJV Serialize obj x 9,660,041 ops/sec ±0.11% (97 runs sampled)
|
|
44
|
+
JSON stringify date x 1,084,008 ops/sec ±0.16% (98 runs sampled)
|
|
45
|
+
fast-json-stringify date format x 1,781,044 ops/sec ±0.48% (99 runs sampled)
|
|
46
|
+
compile-json-stringify date format x 1,086,187 ops/sec ±0.16% (99 runs sampled)
|
|
34
47
|
```
|
|
35
48
|
|
|
36
49
|
#### Table of contents:
|
|
@@ -43,7 +56,7 @@ fast-json-stringify date format x 1,674,498 ops/sec ±0.12% (99 runs sampled)
|
|
|
43
56
|
- <a href="#missingFields">`Missing fields`</a>
|
|
44
57
|
- <a href="#patternProperties">`Pattern Properties`</a>
|
|
45
58
|
- <a href="#additionalProperties">`Additional Properties`</a>
|
|
46
|
-
- <a href="#anyof">`AnyOf`</a>
|
|
59
|
+
- <a href="#anyof">`AnyOf` and `OneOf`</a>
|
|
47
60
|
- <a href="#ref">`Reuse - $ref`</a>
|
|
48
61
|
- <a href="#long">`Long integers`</a>
|
|
49
62
|
- <a href="#integer">`Integers`</a>
|
|
@@ -102,7 +115,7 @@ const stringify = fastJson(mySchema, {
|
|
|
102
115
|
```
|
|
103
116
|
|
|
104
117
|
- `schema`: external schemas references by $ref property. [More details](#ref)
|
|
105
|
-
- `ajv`: ajv instance's settings for those properties that require `ajv`. [More details](#anyof)
|
|
118
|
+
- `ajv`: [ajv v8 instance's settings](https://ajv.js.org/options.html) for those properties that require `ajv`. [More details](#anyof)
|
|
106
119
|
- `rounding`: setup how the `integer` types will be rounded when not integers. [More details](#integer)
|
|
107
120
|
|
|
108
121
|
|
|
@@ -111,7 +124,7 @@ const stringify = fastJson(mySchema, {
|
|
|
111
124
|
<a name="fastJsonStringify"></a>
|
|
112
125
|
### fastJsonStringify(schema)
|
|
113
126
|
|
|
114
|
-
Build a `stringify()` function based on [jsonschema](https://json-schema.org/).
|
|
127
|
+
Build a `stringify()` function based on [jsonschema draft 7 spec](https://json-schema.org/specification-links.html#draft-7).
|
|
115
128
|
|
|
116
129
|
Supported types:
|
|
117
130
|
|
|
@@ -307,11 +320,11 @@ const obj = {
|
|
|
307
320
|
console.log(stringify(obj)) // '{"nickname":"nick","matchfoo":"42","otherfoo":"str","matchnum":3,"nomatchstr":"valar morghulis",nomatchint:"313"}'
|
|
308
321
|
```
|
|
309
322
|
|
|
310
|
-
#### AnyOf
|
|
323
|
+
#### AnyOf and OneOf
|
|
311
324
|
|
|
312
|
-
`fast-json-stringify` supports the anyOf
|
|
325
|
+
`fast-json-stringify` supports the **anyOf** and **oneOf** keywords as defined by JSON schema. Both must be an array of valid JSON schemas. The different schemas will be tested in the specified order. The more schemas `stringify` has to try before finding a match, the slower it will be.
|
|
313
326
|
|
|
314
|
-
*anyOf*
|
|
327
|
+
*anyOf* and *oneOf* use [ajv](https://www.npmjs.com/package/ajv) as a JSON schema validator to find the schema that matches the data. This has an impact on performance—only use it as a last resort.
|
|
315
328
|
|
|
316
329
|
Example:
|
|
317
330
|
```javascript
|
|
@@ -521,46 +534,7 @@ const stringify = fastJson(schema, { schema: externalSchema })
|
|
|
521
534
|
|
|
522
535
|
<a name="long"></a>
|
|
523
536
|
#### Long integers
|
|
524
|
-
By default the library will automatically
|
|
525
|
-
If you can't use BigInts in your environment, long integers (64-bit) are also supported using the [long](https://github.com/dcodeIO/long.js) module.
|
|
526
|
-
Example:
|
|
527
|
-
```javascript
|
|
528
|
-
// => using native BigInt
|
|
529
|
-
const stringify = fastJson({
|
|
530
|
-
title: 'Example Schema',
|
|
531
|
-
type: 'object',
|
|
532
|
-
properties: {
|
|
533
|
-
id: {
|
|
534
|
-
type: 'integer'
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
})
|
|
538
|
-
|
|
539
|
-
const obj = {
|
|
540
|
-
id: 18446744073709551615n
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
console.log(stringify(obj)) // '{"id":18446744073709551615}'
|
|
544
|
-
|
|
545
|
-
// => using the long library
|
|
546
|
-
const Long = require('long')
|
|
547
|
-
|
|
548
|
-
const stringify = fastJson({
|
|
549
|
-
title: 'Example Schema',
|
|
550
|
-
type: 'object',
|
|
551
|
-
properties: {
|
|
552
|
-
id: {
|
|
553
|
-
type: 'integer'
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
})
|
|
557
|
-
|
|
558
|
-
const obj = {
|
|
559
|
-
id: Long.fromString('18446744073709551615', true)
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
console.log(stringify(obj)) // '{"id":18446744073709551615}'
|
|
563
|
-
```
|
|
537
|
+
By default the library will handle automatically [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt).
|
|
564
538
|
|
|
565
539
|
<a name="integer"></a>
|
|
566
540
|
#### Integers
|
package/bench.js
CHANGED
|
@@ -38,6 +38,21 @@ const schemaCJS = {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
const schemaAJVJTD = {
|
|
42
|
+
properties: {
|
|
43
|
+
firstName: {
|
|
44
|
+
type: 'string'
|
|
45
|
+
},
|
|
46
|
+
lastName: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
nullable: true
|
|
49
|
+
},
|
|
50
|
+
age: {
|
|
51
|
+
type: 'uint8'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
const arraySchema = {
|
|
42
57
|
title: 'array schema',
|
|
43
58
|
type: 'array',
|
|
@@ -50,6 +65,10 @@ const arraySchemaCJS = {
|
|
|
50
65
|
items: schemaCJS
|
|
51
66
|
}
|
|
52
67
|
|
|
68
|
+
const arraySchemaAJVJTD = {
|
|
69
|
+
elements: schemaAJVJTD
|
|
70
|
+
}
|
|
71
|
+
|
|
53
72
|
const dateFormatSchema = {
|
|
54
73
|
description: 'Date of birth',
|
|
55
74
|
type: 'string',
|
|
@@ -85,6 +104,12 @@ const stringifyDate = FJS(dateFormatSchema)
|
|
|
85
104
|
const stringifyString = FJS({ type: 'string' })
|
|
86
105
|
let str = ''
|
|
87
106
|
|
|
107
|
+
const Ajv = require('ajv/dist/jtd')
|
|
108
|
+
const ajv = new Ajv()
|
|
109
|
+
const ajvSerialize = ajv.compileSerializer(schemaAJVJTD)
|
|
110
|
+
const ajvSerializeArray = ajv.compileSerializer(arraySchemaAJVJTD)
|
|
111
|
+
const ajvSerializeString = ajv.compileSerializer({ type: 'string' })
|
|
112
|
+
|
|
88
113
|
// eslint-disable-next-line
|
|
89
114
|
for (var i = 0; i < 10000; i++) {
|
|
90
115
|
str += i
|
|
@@ -105,6 +130,9 @@ suite.add('FJS creation', function () {
|
|
|
105
130
|
suite.add('CJS creation', function () {
|
|
106
131
|
CJS(schemaCJS)
|
|
107
132
|
})
|
|
133
|
+
suite.add('AJV Serialize creation', function () {
|
|
134
|
+
ajv.compileSerializer(schemaAJVJTD)
|
|
135
|
+
})
|
|
108
136
|
|
|
109
137
|
suite.add('JSON.stringify array', function () {
|
|
110
138
|
JSON.stringify(multiArray)
|
|
@@ -118,6 +146,10 @@ suite.add('compile-json-stringify array', function () {
|
|
|
118
146
|
CJSStringifyArray(multiArray)
|
|
119
147
|
})
|
|
120
148
|
|
|
149
|
+
suite.add('AJV Serialize array', function () {
|
|
150
|
+
ajvSerializeArray(multiArray)
|
|
151
|
+
})
|
|
152
|
+
|
|
121
153
|
suite.add('JSON.stringify long string', function () {
|
|
122
154
|
JSON.stringify(str)
|
|
123
155
|
})
|
|
@@ -130,6 +162,10 @@ suite.add('compile-json-stringify long string', function () {
|
|
|
130
162
|
CJSStringifyString(str)
|
|
131
163
|
})
|
|
132
164
|
|
|
165
|
+
suite.add('AJV Serialize long string', function () {
|
|
166
|
+
ajvSerializeString(str)
|
|
167
|
+
})
|
|
168
|
+
|
|
133
169
|
suite.add('JSON.stringify short string', function () {
|
|
134
170
|
JSON.stringify('hello world')
|
|
135
171
|
})
|
|
@@ -142,6 +178,10 @@ suite.add('compile-json-stringify short string', function () {
|
|
|
142
178
|
CJSStringifyString('hello world')
|
|
143
179
|
})
|
|
144
180
|
|
|
181
|
+
suite.add('AJV Serialize short string', function () {
|
|
182
|
+
ajvSerializeString('hello world')
|
|
183
|
+
})
|
|
184
|
+
|
|
145
185
|
suite.add('JSON.stringify obj', function () {
|
|
146
186
|
JSON.stringify(obj)
|
|
147
187
|
})
|
|
@@ -154,6 +194,10 @@ suite.add('compile-json-stringify obj', function () {
|
|
|
154
194
|
CJSStringify(obj)
|
|
155
195
|
})
|
|
156
196
|
|
|
197
|
+
suite.add('AJV Serialize obj', function () {
|
|
198
|
+
ajvSerialize(obj)
|
|
199
|
+
})
|
|
200
|
+
|
|
157
201
|
suite.add('JSON stringify date', function () {
|
|
158
202
|
JSON.stringify(date)
|
|
159
203
|
})
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const Ajv = require('ajv')
|
|
4
|
+
const standaloneCode = require('ajv/dist/standalone').default
|
|
5
|
+
const ajvFormats = require('ajv-formats')
|
|
4
6
|
const fs = require('fs')
|
|
5
7
|
const path = require('path')
|
|
6
|
-
const pack = require('ajv-pack')
|
|
7
8
|
|
|
8
9
|
const ajv = new Ajv({
|
|
9
|
-
|
|
10
|
+
addUsedSchema: false,
|
|
11
|
+
allowUnionTypes: true,
|
|
12
|
+
code: {
|
|
13
|
+
source: true,
|
|
14
|
+
lines: true,
|
|
15
|
+
optimize: 3
|
|
16
|
+
}
|
|
10
17
|
})
|
|
18
|
+
ajvFormats(ajv)
|
|
11
19
|
|
|
12
|
-
const
|
|
20
|
+
const schema = require('ajv/lib/refs/json-schema-draft-07.json')
|
|
21
|
+
const validate = ajv.compile(schema)
|
|
22
|
+
const validationCode = standaloneCode(ajv, validate)
|
|
13
23
|
|
|
14
|
-
const moduleCode =
|
|
15
|
-
|
|
16
|
-
function nop () { return true }
|
|
17
|
-
|
|
18
|
-
${pack(ajv, validate).replace(/root\.refVal\[0\]/gm, 'nop')}
|
|
19
|
-
`
|
|
24
|
+
const moduleCode = `/* CODE GENERATED BY '${path.basename(__filename)}' DO NOT EDIT! */\n${validationCode}`
|
|
20
25
|
|
|
21
26
|
fs.writeFileSync(path.join(__dirname, 'schema-validator.js'), moduleCode)
|
package/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
/* eslint no-prototype-builtins: 0 */
|
|
4
4
|
|
|
5
5
|
const Ajv = require('ajv')
|
|
6
|
+
const ajvFormats = require('ajv-formats')
|
|
6
7
|
const merge = require('deepmerge')
|
|
7
8
|
const clone = require('rfdc')({ proto: true })
|
|
8
9
|
const fjsCloned = Symbol('fast-json-stringify.cloned')
|
|
@@ -10,13 +11,6 @@ const fjsCloned = Symbol('fast-json-stringify.cloned')
|
|
|
10
11
|
const validate = require('./schema-validator')
|
|
11
12
|
let stringSimilarity = null
|
|
12
13
|
|
|
13
|
-
let isLong
|
|
14
|
-
try {
|
|
15
|
-
isLong = require('long').isLong
|
|
16
|
-
} catch (e) {
|
|
17
|
-
isLong = null
|
|
18
|
-
}
|
|
19
|
-
|
|
20
14
|
const addComma = `
|
|
21
15
|
if (addComma) {
|
|
22
16
|
json += ','
|
|
@@ -33,7 +27,7 @@ function isValidSchema (schema, name) {
|
|
|
33
27
|
name = ''
|
|
34
28
|
}
|
|
35
29
|
const first = validate.errors[0]
|
|
36
|
-
const err = new Error(`${name}schema is invalid: data${first.
|
|
30
|
+
const err = new Error(`${name}schema is invalid: data${first.instancePath} ${first.message}`)
|
|
37
31
|
err.errors = isValidSchema.errors
|
|
38
32
|
throw err
|
|
39
33
|
}
|
|
@@ -47,10 +41,12 @@ function mergeLocation (source, dest) {
|
|
|
47
41
|
}
|
|
48
42
|
}
|
|
49
43
|
|
|
50
|
-
const
|
|
44
|
+
const arrayItemsReferenceSerializersMap = new Map()
|
|
45
|
+
const objectReferenceSerializersMap = new Map()
|
|
51
46
|
|
|
52
47
|
function build (schema, options) {
|
|
53
|
-
|
|
48
|
+
arrayItemsReferenceSerializersMap.clear()
|
|
49
|
+
objectReferenceSerializersMap.clear()
|
|
54
50
|
options = options || {}
|
|
55
51
|
isValidSchema(schema)
|
|
56
52
|
if (options.schema) {
|
|
@@ -77,7 +73,39 @@ function build (schema, options) {
|
|
|
77
73
|
code += `
|
|
78
74
|
${asFunctions}
|
|
79
75
|
|
|
80
|
-
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Used by schemas that are dependant on calling 'ajv.validate' during runtime,
|
|
79
|
+
* it stores the value of the '$id' property of the schema (if it has it) inside
|
|
80
|
+
* a cache which is used to figure out if the schema was compiled into a validator
|
|
81
|
+
* by ajv on a previous call, if it was then the '$id' string will be used to
|
|
82
|
+
* invoke 'ajv.validate', this allows:
|
|
83
|
+
*
|
|
84
|
+
* 1. Schemas that depend on ajv.validate calls to leverage ajv caching system.
|
|
85
|
+
* 2. To avoid errors, since directly invoking 'ajv.validate' with the same
|
|
86
|
+
* schema (that contains an '$id' property) twice will throw an error.
|
|
87
|
+
*/
|
|
88
|
+
const $validateWithAjv = (function() {
|
|
89
|
+
const cache = new Set()
|
|
90
|
+
|
|
91
|
+
return function (schema, target) {
|
|
92
|
+
const id = schema.$id
|
|
93
|
+
|
|
94
|
+
if (!id) {
|
|
95
|
+
return ajv.validate(schema, target)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const cached = cache.has(id)
|
|
99
|
+
|
|
100
|
+
if (cached) {
|
|
101
|
+
return ajv.validate(id, target)
|
|
102
|
+
} else {
|
|
103
|
+
cache.add(id)
|
|
104
|
+
return ajv.validate(schema, target)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
})()
|
|
108
|
+
|
|
81
109
|
|
|
82
110
|
function parseInteger(int) { return Math.${intParseFunctionName}(int) }
|
|
83
111
|
`
|
|
@@ -136,7 +164,9 @@ function build (schema, options) {
|
|
|
136
164
|
return ${main}
|
|
137
165
|
`
|
|
138
166
|
|
|
139
|
-
const
|
|
167
|
+
const ajvInstance = new Ajv(options.ajv)
|
|
168
|
+
ajvFormats(ajvInstance)
|
|
169
|
+
const dependencies = [ajvInstance]
|
|
140
170
|
const dependenciesName = ['ajv']
|
|
141
171
|
dependenciesName.push(code)
|
|
142
172
|
|
|
@@ -147,7 +177,8 @@ function build (schema, options) {
|
|
|
147
177
|
return dependenciesName
|
|
148
178
|
}
|
|
149
179
|
|
|
150
|
-
|
|
180
|
+
arrayItemsReferenceSerializersMap.clear()
|
|
181
|
+
objectReferenceSerializersMap.clear()
|
|
151
182
|
|
|
152
183
|
return (Function.apply(null, dependenciesName).apply(null, dependencies))
|
|
153
184
|
}
|
|
@@ -239,9 +270,7 @@ function $asNull () {
|
|
|
239
270
|
}
|
|
240
271
|
|
|
241
272
|
function $asInteger (i) {
|
|
242
|
-
if (
|
|
243
|
-
return i.toString()
|
|
244
|
-
} else if (typeof i === 'bigint') {
|
|
273
|
+
if (typeof i === 'bigint') {
|
|
245
274
|
return i.toString()
|
|
246
275
|
} else if (Number.isInteger(i)) {
|
|
247
276
|
return $asNumber(i)
|
|
@@ -399,51 +428,60 @@ function addPatternProperties (location) {
|
|
|
399
428
|
} catch (err) {
|
|
400
429
|
throw new Error(`${err.message}. Found at ${regex} matching ${JSON.stringify(pp[regex])}`)
|
|
401
430
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
431
|
+
|
|
432
|
+
const ifPpKeyExists = `if (/${regex.replace(/\\*\//g, '\\/')}/.test(keys[i])) {`
|
|
433
|
+
|
|
405
434
|
if (type === 'object') {
|
|
406
435
|
code += `${buildObject(ppLocation, '', 'buildObjectPP' + index)}
|
|
436
|
+
${ifPpKeyExists}
|
|
407
437
|
${addComma}
|
|
408
438
|
json += $asString(keys[i]) + ':' + buildObjectPP${index}(obj[keys[i]])
|
|
409
439
|
`
|
|
410
440
|
} else if (type === 'array') {
|
|
411
441
|
code += `${buildArray(ppLocation, '', 'buildArrayPP' + index)}
|
|
442
|
+
${ifPpKeyExists}
|
|
412
443
|
${addComma}
|
|
413
444
|
json += $asString(keys[i]) + ':' + buildArrayPP${index}(obj[keys[i]])
|
|
414
445
|
`
|
|
415
446
|
} else if (type === 'null') {
|
|
416
447
|
code += `
|
|
448
|
+
${ifPpKeyExists}
|
|
417
449
|
${addComma}
|
|
418
450
|
json += $asString(keys[i]) +':null'
|
|
419
451
|
`
|
|
420
452
|
} else if (type === 'string') {
|
|
421
453
|
code += `
|
|
454
|
+
${ifPpKeyExists}
|
|
422
455
|
${addComma}
|
|
423
456
|
json += $asString(keys[i]) + ':' + ${stringSerializer}(obj[keys[i]])
|
|
424
457
|
`
|
|
425
458
|
} else if (type === 'integer') {
|
|
426
459
|
code += `
|
|
460
|
+
${ifPpKeyExists}
|
|
427
461
|
${addComma}
|
|
428
462
|
json += $asString(keys[i]) + ':' + $asInteger(obj[keys[i]])
|
|
429
463
|
`
|
|
430
464
|
} else if (type === 'number') {
|
|
431
465
|
code += `
|
|
466
|
+
${ifPpKeyExists}
|
|
432
467
|
${addComma}
|
|
433
468
|
json += $asString(keys[i]) + ':' + $asNumber(obj[keys[i]])
|
|
434
469
|
`
|
|
435
470
|
} else if (type === 'boolean') {
|
|
436
471
|
code += `
|
|
472
|
+
${ifPpKeyExists}
|
|
437
473
|
${addComma}
|
|
438
474
|
json += $asString(keys[i]) + ':' + $asBoolean(obj[keys[i]])
|
|
439
475
|
`
|
|
440
476
|
} else if (type === undefined) {
|
|
441
477
|
code += `
|
|
478
|
+
${ifPpKeyExists}
|
|
442
479
|
${addComma}
|
|
443
480
|
json += $asString(keys[i]) + ':' + $asAny(obj[keys[i]])
|
|
444
481
|
`
|
|
445
482
|
} else {
|
|
446
483
|
code += `
|
|
484
|
+
${ifPpKeyExists}
|
|
447
485
|
throw new Error('Cannot coerce ' + obj[keys[i]] + ' to ' + ${JSON.stringify(type)})
|
|
448
486
|
`
|
|
449
487
|
}
|
|
@@ -506,22 +544,11 @@ function additionalProperty (location) {
|
|
|
506
544
|
} else if (type === 'integer') {
|
|
507
545
|
code += `
|
|
508
546
|
var t = Number(obj[keys[i]])
|
|
547
|
+
if (!isNaN(t)) {
|
|
548
|
+
${addComma}
|
|
549
|
+
json += $asString(keys[i]) + ':' + t
|
|
550
|
+
}
|
|
509
551
|
`
|
|
510
|
-
if (isLong) {
|
|
511
|
-
code += `
|
|
512
|
-
if (isLong(obj[keys[i]]) || !isNaN(t)) {
|
|
513
|
-
${addComma}
|
|
514
|
-
json += $asString(keys[i]) + ':' + $asInteger(obj[keys[i]])
|
|
515
|
-
}
|
|
516
|
-
`
|
|
517
|
-
} else {
|
|
518
|
-
code += `
|
|
519
|
-
if (!isNaN(t)) {
|
|
520
|
-
${addComma}
|
|
521
|
-
json += $asString(keys[i]) + ':' + t
|
|
522
|
-
}
|
|
523
|
-
`
|
|
524
|
-
}
|
|
525
552
|
} else if (type === 'number') {
|
|
526
553
|
code += `
|
|
527
554
|
var t = Number(obj[keys[i]])
|
|
@@ -723,33 +750,12 @@ function buildCode (location, code, laterCode, name) {
|
|
|
723
750
|
} else if (type === 'integer') {
|
|
724
751
|
code += `
|
|
725
752
|
var rendered = false
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
rendered = true
|
|
733
|
-
} else {
|
|
734
|
-
var t = Number(obj[${sanitized}])
|
|
735
|
-
if (!isNaN(t)) {
|
|
736
|
-
${addComma}
|
|
737
|
-
json += ${asString} + ':' + t
|
|
738
|
-
rendered = true
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
`
|
|
742
|
-
} else {
|
|
743
|
-
code += `
|
|
744
|
-
var t = $asInteger(obj[${sanitized}])
|
|
745
|
-
if (!isNaN(t)) {
|
|
746
|
-
${addComma}
|
|
747
|
-
json += ${asString} + ':' + t
|
|
748
|
-
rendered = true
|
|
749
|
-
}
|
|
750
|
-
`
|
|
751
|
-
}
|
|
752
|
-
code += `
|
|
753
|
+
var t = $asInteger(obj[${sanitized}])
|
|
754
|
+
if (!isNaN(t)) {
|
|
755
|
+
${addComma}
|
|
756
|
+
json += ${asString} + ':' + t
|
|
757
|
+
rendered = true
|
|
758
|
+
}
|
|
753
759
|
if (rendered) {
|
|
754
760
|
`
|
|
755
761
|
} else {
|
|
@@ -807,6 +813,12 @@ function buildCode (location, code, laterCode, name) {
|
|
|
807
813
|
`
|
|
808
814
|
}
|
|
809
815
|
|
|
816
|
+
if (schema.allOf) {
|
|
817
|
+
const builtCode = buildCodeWithAllOfs(location, code, laterCode, name)
|
|
818
|
+
code = builtCode.code
|
|
819
|
+
laterCode = builtCode.laterCode
|
|
820
|
+
}
|
|
821
|
+
|
|
810
822
|
return { code: code, laterCode: laterCode }
|
|
811
823
|
}
|
|
812
824
|
|
|
@@ -863,7 +875,7 @@ function addIfThenElse (location, name) {
|
|
|
863
875
|
let mergedLocation = mergeLocation(location, { schema: merged })
|
|
864
876
|
|
|
865
877
|
code += `
|
|
866
|
-
valid =
|
|
878
|
+
valid = $validateWithAjv(${JSON.stringify(i)}, obj)
|
|
867
879
|
if (valid) {
|
|
868
880
|
`
|
|
869
881
|
if (merged.if && merged.then) {
|
|
@@ -922,6 +934,16 @@ function buildObject (location, code, name) {
|
|
|
922
934
|
}
|
|
923
935
|
`
|
|
924
936
|
}
|
|
937
|
+
|
|
938
|
+
if (objectReferenceSerializersMap.has(schema)) {
|
|
939
|
+
code += `
|
|
940
|
+
return ${objectReferenceSerializersMap.get(schema)}(input)
|
|
941
|
+
}
|
|
942
|
+
`
|
|
943
|
+
return code
|
|
944
|
+
}
|
|
945
|
+
objectReferenceSerializersMap.set(schema, name)
|
|
946
|
+
|
|
925
947
|
code += `
|
|
926
948
|
var obj = ${toJSON('input')}
|
|
927
949
|
var json = '{'
|
|
@@ -978,14 +1000,14 @@ function buildArray (location, code, name, key = null) {
|
|
|
978
1000
|
location = refFinder(schema.items.$ref, location)
|
|
979
1001
|
schema.items = location.schema
|
|
980
1002
|
|
|
981
|
-
if (
|
|
1003
|
+
if (arrayItemsReferenceSerializersMap.has(schema.items)) {
|
|
982
1004
|
code += `
|
|
983
|
-
return ${
|
|
1005
|
+
return ${arrayItemsReferenceSerializersMap.get(schema.items)}(obj)
|
|
984
1006
|
}
|
|
985
1007
|
`
|
|
986
1008
|
return code
|
|
987
1009
|
}
|
|
988
|
-
|
|
1010
|
+
arrayItemsReferenceSerializersMap.set(schema.items, name)
|
|
989
1011
|
}
|
|
990
1012
|
|
|
991
1013
|
let result = { code: '', laterCode: '' }
|
|
@@ -1203,7 +1225,7 @@ function nested (laterCode, name, key, location, subKey, isArray) {
|
|
|
1203
1225
|
// 2. `nested`, through `buildCode`, replaces any reference in object properties with the actual schema
|
|
1204
1226
|
// (see https://github.com/fastify/fast-json-stringify/blob/6da3b3e8ac24b1ca5578223adedb4083b7adf8db/index.js#L631)
|
|
1205
1227
|
code += `
|
|
1206
|
-
${index === 0 ? 'if' : 'else if'}(
|
|
1228
|
+
${index === 0 ? 'if' : 'else if'}($validateWithAjv(${JSON.stringify(location.schema)}, ${testValue}))
|
|
1207
1229
|
${nestedResult.code}
|
|
1208
1230
|
`
|
|
1209
1231
|
laterCode = nestedResult.laterCode
|
|
@@ -1220,7 +1242,7 @@ function nested (laterCode, name, key, location, subKey, isArray) {
|
|
|
1220
1242
|
const testValue = testSerializer !== undefined ? `${testSerializer}(obj${accessor}, true)` : `obj${accessor}`
|
|
1221
1243
|
// see comment on anyOf about dereferencing the schema before calling ajv.validate
|
|
1222
1244
|
code += `
|
|
1223
|
-
${index === 0 ? 'if' : 'else if'}(
|
|
1245
|
+
${index === 0 ? 'if' : 'else if'}($validateWithAjv(${JSON.stringify(location.schema)}, ${testValue}))
|
|
1224
1246
|
${nestedResult.code}
|
|
1225
1247
|
`
|
|
1226
1248
|
laterCode = nestedResult.laterCode
|
|
@@ -1335,7 +1357,9 @@ module.exports.restore = function (debugModeStr, options = {}) {
|
|
|
1335
1357
|
const args = []
|
|
1336
1358
|
if (debugModeStr.startsWith('ajv')) {
|
|
1337
1359
|
dependencies.unshift('ajv')
|
|
1338
|
-
|
|
1360
|
+
const ajvInstance = new Ajv(options.ajv)
|
|
1361
|
+
ajvFormats(ajvInstance)
|
|
1362
|
+
args.push(ajvInstance)
|
|
1339
1363
|
}
|
|
1340
1364
|
|
|
1341
1365
|
// eslint-disable-next-line
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-json-stringify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Stringify your JSON at max speed",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -30,11 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/fastify/fast-json-stringify#readme",
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"ajv-pack": "^0.3.1",
|
|
34
33
|
"benchmark": "^2.1.4",
|
|
35
34
|
"compile-json-stringify": "^0.1.2",
|
|
36
35
|
"is-my-json-valid": "^2.20.0",
|
|
37
|
-
"long": "^4.0.0",
|
|
38
36
|
"moment": "^2.24.0",
|
|
39
37
|
"pre-commit": "^1.2.2",
|
|
40
38
|
"proxyquire": "^2.1.3",
|
|
@@ -45,7 +43,8 @@
|
|
|
45
43
|
"webpack": "^5.40.0"
|
|
46
44
|
},
|
|
47
45
|
"dependencies": {
|
|
48
|
-
"ajv": "^6.
|
|
46
|
+
"ajv": "^8.6.2",
|
|
47
|
+
"ajv-formats": "^2.1.1",
|
|
49
48
|
"deepmerge": "^4.2.2",
|
|
50
49
|
"rfdc": "^1.2.0",
|
|
51
50
|
"string-similarity": "^4.0.1"
|