fast-json-stringify 5.6.1 → 5.7.0
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/README.md +1 -2
- package/index.js +7 -16
- package/lib/serializer.js +11 -2
- package/lib/standalone.js +22 -33
- package/lib/validator.js +19 -0
- package/package.json +5 -4
- package/test/integer.test.js +13 -0
- package/test/ref.test.js +39 -0
package/README.md
CHANGED
|
@@ -689,8 +689,7 @@ console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"F
|
|
|
689
689
|
### Standalone Mode
|
|
690
690
|
|
|
691
691
|
The standalone mode is used to compile the code that can be directly run by `node`
|
|
692
|
-
itself. You need to
|
|
693
|
-
the standalone code to work.
|
|
692
|
+
itself. You need to have `fast-json-stringify` installed for the standalone code to work.
|
|
694
693
|
|
|
695
694
|
```js
|
|
696
695
|
const fs = require('fs')
|
package/index.js
CHANGED
|
@@ -170,18 +170,15 @@ function build (schema, options) {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/* eslint no-new-func: "off" */
|
|
174
|
+
const contextFunc = new Function('validator', 'serializer', contextFunctionCode)
|
|
175
|
+
|
|
173
176
|
if (options.mode === 'standalone') {
|
|
174
|
-
// lazy load
|
|
175
|
-
const isValidatorUsed = context.validatorSchemasIds.size > 0
|
|
176
177
|
const buildStandaloneCode = require('./lib/standalone')
|
|
177
|
-
return buildStandaloneCode(
|
|
178
|
+
return buildStandaloneCode(contextFunc, context, serializer, validator)
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
const contextFunc = new Function('validator', 'serializer', contextFunctionCode)
|
|
182
|
-
const stringifyFunc = contextFunc(validator, serializer)
|
|
183
|
-
|
|
184
|
-
return stringifyFunc
|
|
181
|
+
return contextFunc(validator, serializer)
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
const objectKeywords = [
|
|
@@ -571,12 +568,8 @@ function buildArray (context, location) {
|
|
|
571
568
|
`
|
|
572
569
|
}
|
|
573
570
|
|
|
574
|
-
if (largeArrayMechanism
|
|
575
|
-
if (
|
|
576
|
-
functionCode += `if (arrayLength && arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
|
|
577
|
-
} else {
|
|
578
|
-
throw new Error(`Unsupported large array mechanism ${largeArrayMechanism}`)
|
|
579
|
-
}
|
|
571
|
+
if (largeArrayMechanism === 'json-stringify') {
|
|
572
|
+
functionCode += `if (arrayLength && arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
|
|
580
573
|
}
|
|
581
574
|
|
|
582
575
|
functionCode += `
|
|
@@ -663,8 +656,6 @@ function buildArrayTypeCondition (type, accessor) {
|
|
|
663
656
|
return buildArrayTypeCondition(subType, accessor)
|
|
664
657
|
})
|
|
665
658
|
condition = `(${conditions.join(' || ')})`
|
|
666
|
-
} else {
|
|
667
|
-
throw new Error(`${type} unsupported`)
|
|
668
659
|
}
|
|
669
660
|
}
|
|
670
661
|
return condition
|
package/lib/serializer.js
CHANGED
|
@@ -20,6 +20,7 @@ module.exports = class Serializer {
|
|
|
20
20
|
this.parseInteger = Math.trunc
|
|
21
21
|
break
|
|
22
22
|
}
|
|
23
|
+
this._options = options
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
asInteger (i) {
|
|
@@ -27,7 +28,7 @@ module.exports = class Serializer {
|
|
|
27
28
|
if (i === Infinity || i === -Infinity) {
|
|
28
29
|
throw new Error(`The value "${i}" cannot be converted to an integer.`)
|
|
29
30
|
}
|
|
30
|
-
if ((i
|
|
31
|
+
if (Number.isInteger(i)) {
|
|
31
32
|
return '' + i
|
|
32
33
|
}
|
|
33
34
|
if (Number.isNaN(i)) {
|
|
@@ -54,7 +55,7 @@ module.exports = class Serializer {
|
|
|
54
55
|
if (Number.isNaN(num)) {
|
|
55
56
|
throw new Error(`The value "${i}" cannot be converted to a number.`)
|
|
56
57
|
} else if (!Number.isFinite(num)) {
|
|
57
|
-
return null
|
|
58
|
+
return 'null'
|
|
58
59
|
} else {
|
|
59
60
|
return '' + num
|
|
60
61
|
}
|
|
@@ -156,4 +157,12 @@ module.exports = class Serializer {
|
|
|
156
157
|
}
|
|
157
158
|
return ((point < 32) || (surrogateFound === true)) ? JSON.stringify(str) : '"' + result + '"'
|
|
158
159
|
}
|
|
160
|
+
|
|
161
|
+
getState () {
|
|
162
|
+
return this._options
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static restoreFromState (state) {
|
|
166
|
+
return new Serializer(state)
|
|
167
|
+
}
|
|
159
168
|
}
|
package/lib/standalone.js
CHANGED
|
@@ -1,42 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let defaultAjvSchema = ''
|
|
11
|
-
// we need to export the custom json schema
|
|
12
|
-
const defaultMeta = validator.ajv.defaultMeta()
|
|
13
|
-
if (typeof defaultMeta === 'string') {
|
|
14
|
-
defaultAjvSchema = defaultMeta
|
|
15
|
-
} else {
|
|
16
|
-
defaultAjvSchema = defaultMeta.$id || defaultMeta.id
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
ajvSchemasCode += `const validator = new Validator(${JSON.stringify(options.ajv || {})})\n`
|
|
20
|
-
for (const [id, schema] of Object.entries(validator.ajv.schemas)) {
|
|
21
|
-
// should skip ajv default schema
|
|
22
|
-
if (id === defaultAjvSchema) continue
|
|
23
|
-
ajvSchemasCode += `validator.ajv.addSchema(${JSON.stringify(schema.schema)}, "${id}")\n`
|
|
24
|
-
}
|
|
25
|
-
buildAjvCode = fs.readFileSync(path.join(__dirname, 'validator.js')).toString()
|
|
26
|
-
buildAjvCode = buildAjvCode.replace("'use strict'", '').replace('module.exports = SchemaValidator', '')
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function buildStandaloneCode (contextFunc, context, serializer, validator) {
|
|
4
|
+
let ajvDependencyCode = ''
|
|
5
|
+
if (context.validatorSchemasIds.size > 0) {
|
|
6
|
+
ajvDependencyCode += `const validatorState = ${JSON.stringify(validator.getState())}\n`
|
|
7
|
+
ajvDependencyCode += 'const validator = Validator.restoreFromState(validatorState)\n'
|
|
8
|
+
} else {
|
|
9
|
+
ajvDependencyCode += 'const validator = null\n'
|
|
27
10
|
}
|
|
28
11
|
|
|
29
|
-
const serializerOptions = options && options.rounding ? JSON.stringify({ options: options.rounding }) : ''
|
|
30
12
|
return `
|
|
31
13
|
'use strict'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
14
|
+
const { dependencies } = require('fast-json-stringify/lib/standalone')
|
|
15
|
+
|
|
16
|
+
const { Serializer, Validator } = dependencies
|
|
17
|
+
|
|
18
|
+
const serializerState = ${JSON.stringify(serializer.getState())}
|
|
19
|
+
const serializer = Serializer.restoreFromState(serializerState)
|
|
36
20
|
|
|
37
|
-
${
|
|
21
|
+
${ajvDependencyCode}
|
|
38
22
|
|
|
39
|
-
module.exports =
|
|
23
|
+
module.exports = ${contextFunc.toString()}(validator, serializer)`
|
|
40
24
|
}
|
|
41
25
|
|
|
42
26
|
module.exports = buildStandaloneCode
|
|
27
|
+
|
|
28
|
+
module.exports.dependencies = {
|
|
29
|
+
Serializer: require('./serializer'),
|
|
30
|
+
Validator: require('./validator')
|
|
31
|
+
}
|
package/lib/validator.js
CHANGED
|
@@ -25,6 +25,9 @@ class Validator {
|
|
|
25
25
|
return date instanceof Date
|
|
26
26
|
}
|
|
27
27
|
})
|
|
28
|
+
|
|
29
|
+
this._ajvSchemas = {}
|
|
30
|
+
this._ajvOptions = ajvOptions || {}
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
addSchema (schema, schemaName) {
|
|
@@ -40,6 +43,7 @@ class Validator {
|
|
|
40
43
|
const ajvSchema = clone(schema)
|
|
41
44
|
this.convertSchemaToAjvFormat(ajvSchema)
|
|
42
45
|
this.ajv.addSchema(ajvSchema, schemaKey)
|
|
46
|
+
this._ajvSchemas[schemaKey] = schema
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -70,6 +74,21 @@ class Validator {
|
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
}
|
|
77
|
+
|
|
78
|
+
getState () {
|
|
79
|
+
return {
|
|
80
|
+
ajvOptions: this._ajvOptions,
|
|
81
|
+
ajvSchemas: this._ajvSchemas
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static restoreFromState (state) {
|
|
86
|
+
const validator = new Validator(state.ajvOptions)
|
|
87
|
+
for (const [id, ajvSchema] of Object.entries(state.ajvSchemas)) {
|
|
88
|
+
validator.ajv.addSchema(ajvSchema, id)
|
|
89
|
+
}
|
|
90
|
+
return validator
|
|
91
|
+
}
|
|
73
92
|
}
|
|
74
93
|
|
|
75
94
|
module.exports = Validator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-json-stringify",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0",
|
|
4
4
|
"description": "Stringify your JSON at max speed",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"homepage": "https://github.com/fastify/fast-json-stringify#readme",
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@fastify/pre-commit": "^2.0.2",
|
|
37
|
-
"@sinclair/typebox": "^0.
|
|
37
|
+
"@sinclair/typebox": "^0.26.5",
|
|
38
38
|
"benchmark": "^2.1.4",
|
|
39
39
|
"cli-select": "^1.1.2",
|
|
40
40
|
"compile-json-stringify": "^0.1.2",
|
|
@@ -42,8 +42,9 @@
|
|
|
42
42
|
"simple-git": "^3.7.1",
|
|
43
43
|
"standard": "^17.0.0",
|
|
44
44
|
"tap": "^16.0.1",
|
|
45
|
-
"tsd": "^0.
|
|
46
|
-
"webpack": "^5.40.0"
|
|
45
|
+
"tsd": "^0.28.0",
|
|
46
|
+
"webpack": "^5.40.0",
|
|
47
|
+
"fast-json-stringify": "."
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@fastify/deepmerge": "^1.0.0",
|
package/test/integer.test.js
CHANGED
|
@@ -35,6 +35,18 @@ test('render a float as an integer', (t) => {
|
|
|
35
35
|
}
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
+
test('throws on NaN', (t) => {
|
|
39
|
+
t.plan(1)
|
|
40
|
+
|
|
41
|
+
const schema = {
|
|
42
|
+
title: 'integer',
|
|
43
|
+
type: 'integer'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stringify = build(schema)
|
|
47
|
+
t.throws(() => stringify(NaN), new Error('The value "NaN" cannot be converted to an integer.'))
|
|
48
|
+
})
|
|
49
|
+
|
|
38
50
|
test('render a float as an integer', (t) => {
|
|
39
51
|
const cases = [
|
|
40
52
|
{ input: Math.PI, output: '3' },
|
|
@@ -45,6 +57,7 @@ test('render a float as an integer', (t) => {
|
|
|
45
57
|
{ input: 42, output: '42' },
|
|
46
58
|
{ input: 1.99999, output: '1' },
|
|
47
59
|
{ input: -45.05, output: '-45' },
|
|
60
|
+
{ input: 3333333333333333, output: '3333333333333333' },
|
|
48
61
|
{ input: Math.PI, output: '3', rounding: 'trunc' },
|
|
49
62
|
{ input: 5.0, output: '5', rounding: 'trunc' },
|
|
50
63
|
{ input: null, output: '0', rounding: 'trunc' },
|
package/test/ref.test.js
CHANGED
|
@@ -2078,3 +2078,42 @@ test('should throw an Error if two non-identical schemas with same id are provid
|
|
|
2078
2078
|
|
|
2079
2079
|
t.throws(() => build(schema), new Error('There is already another schema with id inner_schema'))
|
|
2080
2080
|
})
|
|
2081
|
+
|
|
2082
|
+
test('ref internal - throw if schema has definition twice with different shape', (t) => {
|
|
2083
|
+
t.plan(1)
|
|
2084
|
+
|
|
2085
|
+
const schema = {
|
|
2086
|
+
$id: 'test',
|
|
2087
|
+
title: 'object with $ref',
|
|
2088
|
+
definitions: {
|
|
2089
|
+
def: {
|
|
2090
|
+
$id: '#uri',
|
|
2091
|
+
type: 'object',
|
|
2092
|
+
properties: {
|
|
2093
|
+
str: {
|
|
2094
|
+
type: 'string'
|
|
2095
|
+
}
|
|
2096
|
+
},
|
|
2097
|
+
required: ['str']
|
|
2098
|
+
},
|
|
2099
|
+
def2: {
|
|
2100
|
+
$id: '#uri',
|
|
2101
|
+
type: 'object',
|
|
2102
|
+
properties: {
|
|
2103
|
+
num: {
|
|
2104
|
+
type: 'number'
|
|
2105
|
+
}
|
|
2106
|
+
},
|
|
2107
|
+
required: ['num']
|
|
2108
|
+
}
|
|
2109
|
+
},
|
|
2110
|
+
type: 'object',
|
|
2111
|
+
properties: {
|
|
2112
|
+
obj: {
|
|
2113
|
+
$ref: '#uri'
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
t.throws(() => build(schema), Error('There is already another schema with id test##uri'))
|
|
2119
|
+
})
|