Socket
Socket
Sign inDemoInstall

fast-json-stringify

Package Overview
Dependencies
Maintainers
2
Versions
160
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-json-stringify - npm Package Compare versions

Comparing version 2.7.13 to 3.0.0

test/bigint.test.js

44

bench.js

@@ -41,2 +41,17 @@ 'use strict'

const schemaAJVJTD = {
properties: {
firstName: {
type: 'string'
},
lastName: {
type: 'string',
nullable: true
},
age: {
type: 'uint8'
}
}
}
const arraySchema = {

@@ -54,2 +69,6 @@ title: 'array schema',

const arraySchemaAJVJTD = {
elements: schemaAJVJTD
}
const dateFormatSchema = {

@@ -90,2 +109,8 @@ description: 'Date of birth',

const Ajv = require('ajv/dist/jtd')
const ajv = new Ajv()
const ajvSerialize = ajv.compileSerializer(schemaAJVJTD)
const ajvSerializeArray = ajv.compileSerializer(arraySchemaAJVJTD)
const ajvSerializeString = ajv.compileSerializer({ type: 'string' })
// eslint-disable-next-line

@@ -111,2 +136,5 @@ for (var i = 0; i < 10000; i++) {

})
suite.add('AJV Serialize creation', function () {
ajv.compileSerializer(schemaAJVJTD)
})

@@ -125,2 +153,6 @@ suite.add('JSON.stringify array', function () {

suite.add('AJV Serialize array', function () {
ajvSerializeArray(multiArray)
})
suite.add('JSON.stringify long string', function () {

@@ -138,2 +170,6 @@ JSON.stringify(str)

suite.add('AJV Serialize long string', function () {
ajvSerializeString(str)
})
suite.add('JSON.stringify short string', function () {

@@ -151,2 +187,6 @@ JSON.stringify('hello world')

suite.add('AJV Serialize short string', function () {
ajvSerializeString('hello world')
})
suite.add('JSON.stringify obj', function () {

@@ -164,2 +204,6 @@ JSON.stringify(obj)

suite.add('AJV Serialize obj', function () {
ajvSerialize(obj)
})
suite.add('JSON stringify date', function () {

@@ -166,0 +210,0 @@ JSON.stringify(date)

23

build-schema-validator.js
'use strict'
const Ajv = require('ajv')
const standaloneCode = require('ajv/dist/standalone').default
const ajvFormats = require('ajv-formats')
const fs = require('fs')
const path = require('path')
const pack = require('ajv-pack')
const ajv = new Ajv({
sourceCode: true // this option is required by ajv-pack
addUsedSchema: false,
allowUnionTypes: true,
code: {
source: true,
lines: true,
optimize: 3
}
})
ajvFormats(ajv)
const validate = ajv.compile(require('ajv/lib/refs/json-schema-draft-07.json'))
const schema = require('ajv/lib/refs/json-schema-draft-07.json')
const validate = ajv.compile(schema)
const validationCode = standaloneCode(ajv, validate)
const moduleCode = `// This file is autogenerated by ${path.basename(__filename)}, do not edit
const moduleCode = `/* CODE GENERATED BY '${path.basename(__filename)}' DO NOT EDIT! */\n${validationCode}`
function nop () { return true }
${pack(ajv, validate).replace(/root\.refVal\[0\]/gm, 'nop')}
`
fs.writeFileSync(path.join(__dirname, 'schema-validator.js'), moduleCode)

@@ -6,2 +6,3 @@ 'use strict'

const Ajv = require('ajv')
const ajvFormats = require('ajv-formats')
const merge = require('deepmerge')

@@ -14,9 +15,2 @@ const clone = require('rfdc')({ proto: true })

let isLong
try {
isLong = require('long').isLong
} catch (e) {
isLong = null
}
const addComma = `

@@ -38,3 +32,3 @@ if (addComma) {

const first = validate.errors[0]
const err = new Error(`${name}schema is invalid: data${first.dataPath} ${first.message}`)
const err = new Error(`${name}schema is invalid: data${first.instancePath} ${first.message}`)
err.errors = isValidSchema.errors

@@ -85,4 +79,36 @@ throw err

var isLong = ${isLong ? isLong.toString() : false}
/**
* Used by schemas that are dependant on calling 'ajv.validate' during runtime,
* it stores the value of the '$id' property of the schema (if it has it) inside
* a cache which is used to figure out if the schema was compiled into a validator
* by ajv on a previous call, if it was then the '$id' string will be used to
* invoke 'ajv.validate', this allows:
*
* 1. Schemas that depend on ajv.validate calls to leverage ajv caching system.
* 2. To avoid errors, since directly invoking 'ajv.validate' with the same
* schema (that contains an '$id' property) twice will throw an error.
*/
const $validateWithAjv = (function() {
const cache = new Set()
return function (schema, target) {
const id = schema.$id
if (!id) {
return ajv.validate(schema, target)
}
const cached = cache.has(id)
if (cached) {
return ajv.validate(id, target)
} else {
cache.add(id)
return ajv.validate(schema, target)
}
}
})()
function parseInteger(int) { return Math.${intParseFunctionName}(int) }

@@ -145,3 +171,5 @@ `

const dependencies = [new Ajv(options.ajv)]
const ajvInstance = new Ajv(options.ajv)
ajvFormats(ajvInstance)
const dependencies = [ajvInstance]
const dependenciesName = ['ajv']

@@ -250,6 +278,4 @@ dependenciesName.push(code)

function $asInteger (i) {
if (isLong && isLong(i)) {
if (typeof i === 'bigint') {
return i.toString()
} else if (typeof i === 'bigint') {
return i.toString()
} else if (Number.isInteger(i)) {

@@ -527,18 +553,7 @@ return $asNumber(i)

var t = Number(obj[keys[i]])
if (!isNaN(t)) {
${addComma}
json += $asString(keys[i]) + ':' + t
}
`
if (isLong) {
code += `
if (isLong(obj[keys[i]]) || !isNaN(t)) {
${addComma}
json += $asString(keys[i]) + ':' + $asInteger(obj[keys[i]])
}
`
} else {
code += `
if (!isNaN(t)) {
${addComma}
json += $asString(keys[i]) + ':' + t
}
`
}
} else if (type === 'number') {

@@ -745,29 +760,8 @@ code += `

var rendered = false
`
if (isLong) {
code += `
if (isLong(obj[${sanitized}])) {
${addComma}
json += ${asString} + ':' + obj[${sanitized}].toString()
rendered = true
} else {
var t = Number(obj[${sanitized}])
if (!isNaN(t)) {
${addComma}
json += ${asString} + ':' + t
rendered = true
}
}
`
} else {
code += `
var t = $asInteger(obj[${sanitized}])
if (!isNaN(t)) {
${addComma}
json += ${asString} + ':' + t
rendered = true
}
`
}
code += `
var t = $asInteger(obj[${sanitized}])
if (!isNaN(t)) {
${addComma}
json += ${asString} + ':' + t
rendered = true
}
if (rendered) {

@@ -892,3 +886,3 @@ `

code += `
valid = ajv.validate(${JSON.stringify(i)}, obj)
valid = $validateWithAjv(${JSON.stringify(i)}, obj)
if (valid) {

@@ -1243,3 +1237,3 @@ `

code += `
${index === 0 ? 'if' : 'else if'}(ajv.validate(${JSON.stringify(location.schema)}, ${testValue}))
${index === 0 ? 'if' : 'else if'}($validateWithAjv(${JSON.stringify(location.schema)}, ${testValue}))
${nestedResult.code}

@@ -1261,3 +1255,3 @@ `

code += `
${index === 0 ? 'if' : 'else if'}(ajv.validate(${JSON.stringify(location.schema)}, ${testValue}))
${index === 0 ? 'if' : 'else if'}($validateWithAjv(${JSON.stringify(location.schema)}, ${testValue}))
${nestedResult.code}

@@ -1377,3 +1371,5 @@ `

dependencies.unshift('ajv')
args.push(new Ajv(options.ajv))
const ajvInstance = new Ajv(options.ajv)
ajvFormats(ajvInstance)
args.push(ajvInstance)
}

@@ -1380,0 +1376,0 @@

{
"name": "fast-json-stringify",
"version": "2.7.13",
"version": "3.0.0",
"description": "Stringify your JSON at max speed",

@@ -33,7 +33,5 @@ "main": "index.js",

"devDependencies": {
"ajv-pack": "^0.3.1",
"benchmark": "^2.1.4",
"compile-json-stringify": "^0.1.2",
"is-my-json-valid": "^2.20.0",
"long": "^4.0.0",
"moment": "^2.24.0",

@@ -49,3 +47,4 @@ "pre-commit": "^1.2.2",

"dependencies": {
"ajv": "^6.11.0",
"ajv": "^8.6.2",
"ajv-formats": "^2.1.1",
"deepmerge": "^4.2.2",

@@ -52,0 +51,0 @@ "rfdc": "^1.2.0",

@@ -10,4 +10,11 @@ # fast-json-stringify

__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads. Its performance advantage shrinks as your payload grows. 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`.
__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads.
Its performance advantage shrinks as your payload grows.
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`.
### How it works
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.
##### Benchmarks

@@ -19,18 +26,24 @@

```
FJS creation x 6,040 ops/sec ±1.17% (91 runs sampled)
JSON.stringify array x 5,519 ops/sec ±0.08% (99 runs sampled)
fast-json-stringify array x 7,143 ops/sec ±0.14% (97 runs sampled)
JSON.stringify long string x 16,438 ops/sec ±0.32% (98 runs sampled)
fast-json-stringify long string x 16,457 ops/sec ±0.09% (97 runs sampled)
JSON.stringify short string x 12,061,258 ops/sec ±0.32% (97 runs sampled)
fast-json-stringify short string x 35,531,071 ops/sec ±0.17% (94 runs sampled)
JSON.stringify obj x 3,079,746 ops/sec ±0.09% (95 runs sampled)
fast-json-stringify obj x 7,721,569 ops/sec ±0.12% (98 runs sampled)
JSON stringify date x 1,149,786 ops/sec ±0.10% (99 runs sampled)
fast-json-stringify date format x 1,674,498 ops/sec ±0.12% (99 runs sampled)
FJS creation x 8,443 ops/sec ±1.01% (90 runs sampled)
CJS creation x 183,219 ops/sec ±0.13% (96 runs sampled)
AJV Serialize creation x 83,541,848 ops/sec ±0.24% (98 runs sampled)
JSON.stringify array x 5,363 ops/sec ±0.11% (100 runs sampled)
fast-json-stringify array x 6,747 ops/sec ±0.13% (98 runs sampled)
compile-json-stringify array x 7,121 ops/sec ±0.42% (98 runs sampled)
AJV Serialize array x 7,533 ops/sec ±0.13% (98 runs sampled)
JSON.stringify long string x 16,461 ops/sec ±0.12% (98 runs sampled)
fast-json-stringify long string x 16,443 ops/sec ±0.37% (99 runs sampled)
compile-json-stringify long string x 16,458 ops/sec ±0.09% (98 runs sampled)
AJV Serialize long string x 21,433 ops/sec ±0.08% (95 runs sampled)
JSON.stringify short string x 12,035,664 ops/sec ±0.62% (96 runs sampled)
fast-json-stringify short string x 38,281,060 ops/sec ±0.24% (98 runs sampled)
compile-json-stringify short string x 32,388,037 ops/sec ±0.27% (97 runs sampled)
AJV Serialize short string x 32,288,612 ops/sec ±0.32% (95 runs sampled)
JSON.stringify obj x 3,068,185 ops/sec ±0.16% (98 runs sampled)
fast-json-stringify obj x 10,082,694 ops/sec ±0.10% (97 runs sampled)
compile-json-stringify obj x 17,037,963 ops/sec ±1.17% (97 runs sampled)
AJV Serialize obj x 9,660,041 ops/sec ±0.11% (97 runs sampled)
JSON stringify date x 1,084,008 ops/sec ±0.16% (98 runs sampled)
fast-json-stringify date format x 1,781,044 ops/sec ±0.48% (99 runs sampled)
compile-json-stringify date format x 1,086,187 ops/sec ±0.16% (99 runs sampled)
```

@@ -107,3 +120,3 @@

- `schema`: external schemas references by $ref property. [More details](#ref)
- `ajv`: ajv instance's settings for those properties that require `ajv`. [More details](#anyof)
- `ajv`: [ajv v8 instance's settings](https://ajv.js.org/options.html) for those properties that require `ajv`. [More details](#anyof)
- `rounding`: setup how the `integer` types will be rounded when not integers. [More details](#integer)

@@ -117,3 +130,3 @@

Build a `stringify()` function based on [jsonschema](https://json-schema.org/).
Build a `stringify()` function based on [jsonschema draft 7 spec](https://json-schema.org/specification-links.html#draft-7).

@@ -528,43 +541,4 @@ Supported types:

#### Long integers
By default the library will automatically handle [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) from Node.js v10.3 and above.
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.
Example:
```javascript
// => using native BigInt
const stringify = fastJson({
title: 'Example Schema',
type: 'object',
properties: {
id: {
type: 'integer'
}
}
})
By default the library will handle automatically [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt).
const obj = {
id: 18446744073709551615n
}
console.log(stringify(obj)) // '{"id":18446744073709551615}'
// => using the long library
const Long = require('long')
const stringify = fastJson({
title: 'Example Schema',
type: 'object',
properties: {
id: {
type: 'integer'
}
}
})
const obj = {
id: Long.fromString('18446744073709551615', true)
}
console.log(stringify(obj)) // '{"id":18446744073709551615}'
```
<a name="integer"></a>

@@ -571,0 +545,0 @@ #### Integers

@@ -111,3 +111,3 @@ 'use strict'

} catch (e) {
t.equal(e.message, 'schema is invalid: data.allOf should NOT have fewer than 1 items')
t.equal(e.message, 'schema is invalid: data/allOf must NOT have fewer than 1 items')
}

@@ -114,0 +114,0 @@ })

@@ -66,1 +66,27 @@ 'use strict'

})
test('to string auto-consistent with ajv-formats', t => {
t.plan(3)
const debugMode = fjs({
title: 'object with multiple types field and format keyword',
type: 'object',
properties: {
str: {
anyOf: [{
type: 'string',
format: 'email'
}, {
type: 'boolean'
}]
}
}
}, { debugMode: 1 })
t.type(debugMode, Array)
const str = debugMode.toString()
const compiled = fjs.restore(str)
const tobe = JSON.stringify({ str: 'foo@bar.com' })
t.same(compiled({ str: 'foo@bar.com' }), tobe)
t.same(compiled({ str: 'foo' }), JSON.stringify({ str: null }), 'invalid format is ignored')
})

@@ -11,2 +11,3 @@ 'use strict'

if: {
type: 'object',
properties: {

@@ -17,2 +18,3 @@ kind: { type: 'string', enum: ['foobar'] }

then: {
type: 'object',
properties: {

@@ -35,2 +37,3 @@ kind: { type: 'string', enum: ['foobar'] },

else: {
type: 'object',
properties: {

@@ -58,2 +61,3 @@ kind: { type: 'string', enum: ['greeting'] },

if: {
type: 'object',
properties: {

@@ -65,2 +69,3 @@ kind: { type: 'string', enum: ['foobar', 'greeting'] }

if: {
type: 'object',
properties: {

@@ -71,2 +76,3 @@ kind: { type: 'string', enum: ['foobar'] }

then: {
type: 'object',
properties: {

@@ -89,2 +95,3 @@ kind: { type: 'string', enum: ['foobar'] },

else: {
type: 'object',
properties: {

@@ -98,2 +105,3 @@ kind: { type: 'string', enum: ['greeting'] },

else: {
type: 'object',
properties: {

@@ -111,2 +119,3 @@ kind: { type: 'string', enum: ['alphabet'] },

if: {
type: 'object',
properties: {

@@ -117,2 +126,3 @@ kind: { type: 'string', enum: ['foobar'] }

then: {
type: 'object',
properties: {

@@ -136,2 +146,3 @@ kind: { type: 'string', enum: ['foobar'] },

if: {
type: 'object',
properties: {

@@ -142,2 +153,3 @@ kind: { type: 'string', enum: ['greeting'] }

then: {
type: 'object',
properties: {

@@ -150,2 +162,3 @@ kind: { type: 'string', enum: ['greeting'] },

else: {
type: 'object',
properties: {

@@ -170,2 +183,3 @@ kind: { type: 'string', enum: ['alphabet'] },

if: {
type: 'object',
properties: {

@@ -176,2 +190,3 @@ kind: { type: 'string', enum: ['foobar'] }

then: {
type: 'object',
properties: {

@@ -328,3 +343,3 @@ kind: { type: 'string', enum: ['foobar'] },

const stringify = build(JSON.parse(JSON.stringify(test.schema)))
const stringify = build(JSON.parse(JSON.stringify(test.schema)), { ajv: { strictTypes: false } })
const serialized = stringify(test.input)

@@ -331,0 +346,0 @@ t.equal(serialized, test.expected)

@@ -5,6 +5,4 @@ 'use strict'

const test = t.test
const semver = require('semver')
const validator = require('is-my-json-valid')
const proxyquire = require('proxyquire')
const build = proxyquire('..', { long: null })
const build = require('..')
const ROUNDING_TYPES = ['ceil', 'floor', 'round']

@@ -140,9 +138,2 @@

if (semver.gt(process.versions.node, '10.3.0')) {
require('./bigint')(t.test, build)
} else {
t.pass('Skip because Node version < 10.4')
t.end()
}
test('should round integer object parameter', t => {

@@ -149,0 +140,0 @@ t.plan(2)

@@ -100,3 +100,3 @@ 'use strict'

nullableObject: [{ type: 'object', nullable: true }, null, null],
complexObject: [complexObject, complexData, complexExpectedResult]
complexObject: [complexObject, complexData, complexExpectedResult, { ajv: { allowUnionTypes: true } }]
}

@@ -108,5 +108,10 @@

const stringifier = build(testSet[key][0])
const data = testSet[key][1]
const expected = testSet[key][2]
const [
schema,
data,
expected,
extraOptions
] = testSet[key]
const stringifier = build(schema, extraOptions)
const result = stringifier(data)

@@ -113,0 +118,0 @@ t.same(JSON.parse(result), expected)

@@ -158,1 +158,40 @@ 'use strict'

})
test('must not mutate items referred by $ref', t => {
t.plan(2)
const firstSchema = {
$id: 'example1',
type: 'object',
properties: {
name: {
type: 'string'
}
}
}
const reusedSchema = {
$id: 'example2',
type: 'object',
properties: {
name: {
oneOf: [
{
$ref: 'example1'
}
]
}
}
}
const clonedSchema = clone(firstSchema)
const stringify = build(reusedSchema, {
schema: {
[firstSchema.$id]: firstSchema
}
})
const value = stringify({ name: { name: 'foo' } })
t.equal(value, '{"name":{"name":"foo"}}')
t.same(firstSchema, clonedSchema)
})

@@ -6,3 +6,5 @@ {

"rootDir": "../..",
"strict": true
"strict": true,
"target": "ES2015",
"moduleResolution": "node"
},

@@ -9,0 +11,0 @@ "include": [

@@ -20,3 +20,3 @@ 'use strict'

const stringify = build(schema)
const stringify = build(schema, { ajv: { allowUnionTypes: true } })

@@ -332,3 +332,3 @@ const value = stringify({

}
const stringify = build(schema)
const stringify = build(schema, { ajv: { allowUnionTypes: true } })

@@ -335,0 +335,0 @@ try {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc