Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

fast-json-stringify

Package Overview
Dependencies
Maintainers
11
Versions
166
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
6.1.1
to
6.2.0
+57
test/json-add-comma.test.js
'use strict'
const { test } = require('node:test')
const build = require('..')
test('additionalProperties: false', (t) => {
t.plan(1)
const stringify = build({
title: 'additionalProperties',
type: 'object',
properties: {
foo: {
type: 'string'
}
},
additionalProperties: false
})
const obj = { foo: 'a', bar: 'b', baz: 'c' }
t.assert.equal(stringify(obj), '{"foo":"a"}')
})
test('additionalProperties: {}', (t) => {
t.plan(1)
const stringify = build({
title: 'additionalProperties',
type: 'object',
properties: {
foo: {
type: 'string'
}
},
additionalProperties: {}
})
const obj = { foo: 'a', bar: 'b', baz: 'c' }
t.assert.equal(stringify(obj), '{"foo":"a","bar":"b","baz":"c"}')
})
test('additionalProperties: {type: string}', (t) => {
t.plan(1)
const stringify = build({
title: 'additionalProperties',
type: 'object',
properties: {
foo: {
type: 'string'
}
},
additionalProperties: {
type: 'string'
}
})
const obj = { foo: 'a', bar: 'b', baz: 'c' }
t.assert.equal(stringify(obj), '{"foo":"a","bar":"b","baz":"c"}')
})
+5
-0

@@ -17,2 +17,7 @@ name: CI

# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
permissions:

@@ -19,0 +24,0 @@ contents: read

+21
-7
'use strict'
const benchmark = require('benchmark')
const suite = new benchmark.Suite()
const { Bench } = require('tinybench')
const suite = new Bench({
name: 'Library Comparison Benchmarks',
setup: (_task, mode) => {
// Run the garbage collector before warmup at each cycle
if (mode === 'warmup' && typeof globalThis.gc === 'function') {
globalThis.gc()
}
}
})

@@ -303,8 +311,14 @@ const STR_LEN = 1e4

suite.on('cycle', cycle)
suite.run().then(() => {
for (const task of suite.tasks) {
const hz = task.result.hz // ops/sec
const rme = task.result.rme // relative margin of error (%)
const samples = task.result.samples.length
suite.run()
const formattedHz = hz.toLocaleString('en-US', { maximumFractionDigits: 0 })
const formattedRme = rme.toFixed(2)
function cycle (e) {
console.log(e.target.toString())
}
const output = `${task.name} x ${formattedHz} ops/sec ±${formattedRme}% (${samples} runs sampled)`
console.log(output)
}
}).catch(err => console.error(`Error: ${err.message}`))

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

const Benchmark = require('benchmark')
Benchmark.options.minSamples = 100
const { Bench } = require('tinybench')
const suite = Benchmark.Suite()
const bench = new Bench({
name: benchmark.name,
setup: (_task, mode) => {
// Run the garbage collector before warmup at each cycle
if (mode === 'warmup' && typeof globalThis.gc === 'function') {
globalThis.gc()
}
}
})

@@ -14,10 +21,15 @@ const FJS = require('..')

suite
.add(benchmark.name, () => {
stringify(benchmark.input)
})
.on('cycle', (event) => {
parentPort.postMessage(String(event.target))
})
.on('complete', () => {})
.run()
bench.add(benchmark.name, () => {
stringify(benchmark.input)
}).run().then(() => {
const task = bench.tasks[0]
const hz = task.result.hz // ops/sec
const rme = task.result.rme // relative margin of error (%)
const samples = task.result.samples.length
const formattedHz = hz.toLocaleString('en-US', { maximumFractionDigits: 0 })
const formattedRme = rme.toFixed(2)
const output = `${task.name} x ${formattedHz} ops/sec ±${formattedRme}% (${samples} runs sampled)`
parentPort.postMessage(output)
}).catch(err => parentPort.postMessage(`Error: ${err.message}`))
+330
-132

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

const validRoundingMethods = [
const validRoundingMethods = new Set([
'floor',

@@ -39,8 +39,8 @@ 'ceil',

'trunc'
]
])
const validLargeArrayMechanisms = [
const validLargeArrayMechanisms = new Set([
'default',
'json-stringify'
]
])

@@ -99,2 +99,10 @@ let schemaIdCounter = 0

function getSafeSchemaRef (context, location) {
let schemaRef = location.getSchemaRef() || ''
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '') || '#'
}
return schemaRef
}
function build (schema, options) {

@@ -113,3 +121,7 @@ isValidSchema(schema)

validatorSchemasIds: new Set(),
mergedSchemasIds: new Map()
mergedSchemasIds: new Map(),
recursiveSchemas: new Set(),
recursivePaths: new Set(),
buildingSet: new Set(),
uid: 0
}

@@ -134,3 +146,3 @@

if (options.rounding) {
if (!validRoundingMethods.includes(options.rounding)) {
if (!validRoundingMethods.has(options.rounding)) {
throw new Error(`Unsupported integer rounding method ${options.rounding}`)

@@ -141,3 +153,3 @@ }

if (options.largeArrayMechanism) {
if (validLargeArrayMechanisms.includes(options.largeArrayMechanism)) {
if (validLargeArrayMechanisms.has(options.largeArrayMechanism)) {
largeArrayMechanism = options.largeArrayMechanism

@@ -150,7 +162,10 @@ } else {

if (options.largeArraySize) {
if (typeof options.largeArraySize === 'string' && Number.isFinite(Number.parseInt(options.largeArraySize, 10))) {
largeArraySize = Number.parseInt(options.largeArraySize, 10)
} else if (typeof options.largeArraySize === 'number' && Number.isInteger(options.largeArraySize)) {
const largeArraySizeType = typeof options.largeArraySize
let parsedNumber
if (largeArraySizeType === 'string' && Number.isFinite((parsedNumber = Number.parseInt(options.largeArraySize, 10)))) {
largeArraySize = parsedNumber
} else if (largeArraySizeType === 'number' && Number.isInteger(options.largeArraySize)) {
largeArraySize = options.largeArraySize
} else if (typeof options.largeArraySize === 'bigint') {
} else if (largeArraySizeType === 'bigint') {
largeArraySize = Number(options.largeArraySize)

@@ -163,2 +178,3 @@ } else {

const location = new Location(schema, context.rootSchemaId)
detectRecursiveSchemas(context, location)
const code = buildValue(context, location, 'input')

@@ -294,3 +310,3 @@

function buildExtraObjectPropertiesSerializer (context, location, addComma) {
function buildExtraObjectPropertiesSerializer (context, location, addComma, objVar) {
const schema = location.schema

@@ -301,3 +317,3 @@ const propertiesKeys = Object.keys(schema.properties || {})

const propertiesKeys = ${JSON.stringify(propertiesKeys)}
for (const [key, value] of Object.entries(obj)) {
for (const [key, value] of Object.entries(${objVar})) {
if (

@@ -354,3 +370,3 @@ propertiesKeys.includes(key) ||

function buildInnerObject (context, location) {
function buildInnerObject (context, location, objVar) {
const schema = location.schema

@@ -369,5 +385,4 @@

)
const hasRequiredProperties = requiredProperties.includes(propertiesKeys[0])
let code = 'let value\n'
let code = ''

@@ -377,12 +392,15 @@ for (const key of requiredProperties) {

const sanitizedKey = JSON.stringify(key)
code += `if (obj[${sanitizedKey}] === undefined) throw new Error('${sanitizedKey.replace(/'/g, '\\\'')} is required!')\n`
code += `if (${objVar}[${sanitizedKey}] === undefined) throw new Error('${sanitizedKey.replace(/'/g, '\\\'')} is required!')\n`
}
}
code += 'let json = JSON_STR_BEGIN_OBJECT\n'
code += 'json += JSON_STR_BEGIN_OBJECT\n'
const localUid = context.uid++
let addComma = ''
if (!hasRequiredProperties) {
code += 'let addComma = false\n'
addComma = '!addComma && (addComma = true) || (json += JSON_STR_COMMA)'
const needsRuntimeComma = propertiesKeys.length > 1 || schema.patternProperties || (schema.additionalProperties !== undefined && schema.additionalProperties !== false)
if (needsRuntimeComma) {
code += `let addComma_${localUid} = false\n`
addComma = `!addComma_${localUid} && (addComma_${localUid} = true) || (json += JSON_STR_COMMA)`
}

@@ -397,2 +415,3 @@

const sanitizedKey = JSON.stringify(key)
const value = `value_${key.replace(/[^a-zA-Z0-9]/g, '_')}_${context.uid++}`
const defaultValue = propertyLocation.schema.default

@@ -402,7 +421,7 @@ const isRequired = requiredProperties.includes(key)

code += `
value = obj[${sanitizedKey}]
if (value !== undefined) {
const ${value} = ${objVar}[${sanitizedKey}]
if (${value} !== undefined) {
${addComma}
json += ${JSON.stringify(sanitizedKey + ':')}
${buildValue(context, propertyLocation, 'value')}
${buildValue(context, propertyLocation, `${value}`)}
}`

@@ -424,14 +443,10 @@

}
if (hasRequiredProperties) {
addComma = 'json += \',\''
}
}
if (schema.patternProperties || schema.additionalProperties) {
code += buildExtraObjectPropertiesSerializer(context, location, addComma)
code += buildExtraObjectPropertiesSerializer(context, location, addComma, objVar)
}
code += `
return json + JSON_STR_END_OBJECT
json += JSON_STR_END_OBJECT
`

@@ -442,3 +457,3 @@ return code

function mergeLocations (context, mergedSchemaId, mergedLocations) {
for (let i = 0; i < mergedLocations.length; i++) {
for (let i = 0, mergedLocationsLength = mergedLocations.length; i < mergedLocationsLength; i++) {
const location = mergedLocations[i]

@@ -505,36 +520,53 @@ const schema = location.schema

function buildObject (context, location) {
function buildObject (context, location, input) {
const schema = location.schema
if (context.functionsNamesBySchema.has(schema)) {
return context.functionsNamesBySchema.get(schema)
const funcName = context.functionsNamesBySchema.get(schema)
return `json += ${funcName}(${input})`
}
const functionName = generateFuncName(context)
context.functionsNamesBySchema.set(schema, functionName)
const nullable = schema.nullable === true
let schemaRef = location.getSchemaRef()
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '')
}
const schemaId = location.schemaId || ''
const jsonPointer = location.jsonPointer || ''
const fullPath = `${schemaId}#${jsonPointer}`
let functionCode = `
`
if (context.recursivePaths.has(fullPath) || context.buildingSet.has(schema)) {
const functionName = generateFuncName(context)
context.functionsNamesBySchema.set(schema, functionName)
const nullable = schema.nullable === true
functionCode += `
// ${schemaRef}
function ${functionName} (input) {
const obj = ${toJSON('input')}
${!nullable ? 'if (obj === null) return JSON_STR_EMPTY_OBJECT' : ''}
const schemaRef = getSafeSchemaRef(context, location)
${buildInnerObject(context, location)}
const functionCode = `
// ${schemaRef}
function ${functionName} (input) {
const obj = ${toJSON('input')}
if (obj === null) return ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_OBJECT'}
let json = ''
${buildInnerObject(context, location, 'obj')}
return json
}
`
context.functions.push(functionCode)
return `json += ${functionName}(${input})`
}
context.buildingSet.add(schema)
const objVar = `obj_${context.uid++}`
const code = `
const ${objVar} = ${toJSON(input)}
if (${objVar} === null) {
json += ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_OBJECT'}
} else {
${buildInnerObject(context, location, objVar)}
}
`
context.functions.push(functionCode)
return functionName
context.buildingSet.delete(schema)
return code
}
function buildArray (context, location) {
function buildArray (context, location, input) {
const schema = location.schema

@@ -552,21 +584,26 @@

if (context.functionsNamesBySchema.has(schema)) {
return context.functionsNamesBySchema.get(schema)
const funcName = context.functionsNamesBySchema.get(schema)
return `json += ${funcName}(${input})`
}
const functionName = generateFuncName(context)
context.functionsNamesBySchema.set(schema, functionName)
const nullable = schema.nullable === true
let schemaRef = location.getSchemaRef()
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '')
}
const schemaId = location.schemaId || ''
const jsonPointer = location.jsonPointer || ''
const fullPath = `${schemaId}#${jsonPointer}`
let functionCode = `
if (context.recursivePaths.has(fullPath) || context.buildingSet.has(schema)) {
const functionName = generateFuncName(context)
context.functionsNamesBySchema.set(schema, functionName)
const schemaRef = getSafeSchemaRef(context, location)
let functionCode = `
function ${functionName} (obj) {
// ${schemaRef}
let json = ''
`
const nullable = schema.nullable === true
functionCode += `
${!nullable ? 'if (obj === null) return JSON_STR_EMPTY_ARRAY' : ''}
functionCode += `
if (obj === null) return ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_ARRAY'}
if (!Array.isArray(obj)) {

@@ -578,4 +615,4 @@ throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)

if (!schema.additionalItems && Array.isArray(itemsSchema)) {
functionCode += `
if (!schema.additionalItems && Array.isArray(itemsSchema)) {
functionCode += `
if (arrayLength > ${itemsSchema.length}) {

@@ -585,26 +622,103 @@ throw new Error(\`Item at ${itemsSchema.length} does not match schema definition.\`)

`
}
if (largeArrayMechanism === 'json-stringify') {
functionCode += `if (arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
}
functionCode += `
json += JSON_STR_BEGIN_ARRAY
`
if (Array.isArray(itemsSchema)) {
for (let i = 0, itemsSchemaLength = itemsSchema.length; i < itemsSchemaLength; i++) {
const item = itemsSchema[i]
const value = `value_${i}`
functionCode += `const ${value} = obj[${i}]`
const tmpRes = buildValue(context, itemsLocation.getPropertyLocation(i), value)
functionCode += `
if (${i} < arrayLength) {
if (${buildArrayTypeCondition(item.type, value)}) {
if (${i}) {
json += JSON_STR_COMMA
}
${tmpRes}
} else {
throw new Error(\`Item at ${i} does not match schema definition.\`)
}
}
`
}
if (schema.additionalItems) {
functionCode += `
for (let i = ${itemsSchema.length}; i < arrayLength; i++) {
if (i) {
json += JSON_STR_COMMA
}
json += JSON.stringify(obj[i])
}`
}
} else {
const code = buildValue(context, itemsLocation, 'value')
functionCode += `
for (let i = 0; i < arrayLength; i++) {
if (i) {
json += JSON_STR_COMMA
}
const value = obj[i]
${code}
}`
}
functionCode += `
return json + JSON_STR_END_ARRAY
}`
context.functions.push(functionCode)
return `json += ${functionName}(${input})`
}
context.buildingSet.add(schema)
const safeSchemaRef = getSafeSchemaRef(context, location)
const objVar = `obj_${context.uid++}`
let inlinedCode = `
const ${objVar} = ${input}
if (${objVar} === null) {
json += ${nullable ? 'JSON_STR_NULL' : 'JSON_STR_EMPTY_ARRAY'}
} else if (!Array.isArray(${objVar})) {
throw new TypeError(\`The value of '${safeSchemaRef}' does not match schema definition.\`)
} else {
const arrayLength_${objVar} = ${objVar}.length
`
if (!schema.additionalItems && Array.isArray(itemsSchema)) {
inlinedCode += `
if (arrayLength_${objVar} > ${itemsSchema.length}) {
throw new Error(\`Item at ${itemsSchema.length} does not match schema definition.\`)
}
`
}
if (largeArrayMechanism === 'json-stringify') {
functionCode += `if (arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
inlinedCode += `if (arrayLength_${objVar} >= ${largeArraySize}) json += JSON.stringify(${objVar})\n else {`
}
functionCode += `
const arrayEnd = arrayLength - 1
let value
let json = ''
inlinedCode += `
json += JSON_STR_BEGIN_ARRAY
`
if (Array.isArray(itemsSchema)) {
for (let i = 0; i < itemsSchema.length; i++) {
const localUid = context.uid++
inlinedCode += `let addComma_${localUid} = false\n`
for (let i = 0, itemsSchemaLength = itemsSchema.length; i < itemsSchemaLength; i++) {
const item = itemsSchema[i]
functionCode += `value = obj[${i}]`
const tmpRes = buildValue(context, itemsLocation.getPropertyLocation(i), 'value')
functionCode += `
if (${i} < arrayLength) {
if (${buildArrayTypeCondition(item.type, 'value')}) {
const value = `value_${i}_${context.uid++}`
inlinedCode += `const ${value} = ${objVar}[${i}]`
const tmpRes = buildValue(context, itemsLocation.getPropertyLocation(i), value)
inlinedCode += `
if (${i} < arrayLength_${objVar}) {
if (${buildArrayTypeCondition(item.type, value)}) {
!addComma_${localUid} && (addComma_${localUid} = true) || (json += JSON_STR_COMMA)
${tmpRes}
if (${i} < arrayEnd) {
json += JSON_STR_COMMA
}
} else {

@@ -618,9 +732,6 @@ throw new Error(\`Item at ${i} does not match schema definition.\`)

if (schema.additionalItems) {
functionCode += `
for (let i = ${itemsSchema.length}; i < arrayLength; i++) {
value = obj[i]
json += JSON.stringify(value)
if (i < arrayEnd) {
json += JSON_STR_COMMA
}
inlinedCode += `
for (let i = ${itemsSchema.length}; i < arrayLength_${objVar}; i++) {
!addComma_${localUid} && (addComma_${localUid} = true) || (json += JSON_STR_COMMA)
json += JSON.stringify(${objVar}[i])
}`

@@ -630,18 +741,23 @@ }

const code = buildValue(context, itemsLocation, 'value')
functionCode += `
for (let i = 0; i < arrayLength; i++) {
value = obj[i]
${code}
if (i < arrayEnd) {
inlinedCode += `
for (let i = 0; i < arrayLength_${objVar}; i++) {
if (i) {
json += JSON_STR_COMMA
}
const value = ${objVar}[i]
${code}
}`
}
functionCode += `
return JSON_STR_BEGIN_ARRAY + json + JSON_STR_END_ARRAY
}`
inlinedCode += `
json += JSON_STR_END_ARRAY
`
context.functions.push(functionCode)
return functionName
if (largeArrayMechanism === 'json-stringify') {
inlinedCode += '}'
}
inlinedCode += '}'
context.buildingSet.delete(schema)
return inlinedCode
}

@@ -653,29 +769,29 @@

case 'null':
condition = 'value === null'
condition = `${accessor} === null`
break
case 'string':
condition = `typeof value === 'string' ||
value === null ||
value instanceof Date ||
value instanceof RegExp ||
condition = `typeof ${accessor} === 'string' ||
${accessor} === null ||
${accessor} instanceof Date ||
${accessor} instanceof RegExp ||
(
typeof value === "object" &&
typeof value.toString === "function" &&
value.toString !== Object.prototype.toString
typeof ${accessor} === "object" &&
typeof ${accessor}.toString === "function" &&
${accessor}.toString !== Object.prototype.toString
)`
break
case 'integer':
condition = 'Number.isInteger(value)'
condition = `Number.isInteger(${accessor})`
break
case 'number':
condition = 'Number.isFinite(value)'
condition = `Number.isFinite(${accessor})`
break
case 'boolean':
condition = 'typeof value === \'boolean\''
condition = `typeof ${accessor} === 'boolean'`
break
case 'object':
condition = 'value && typeof value === \'object\' && value.constructor === Object'
condition = `${accessor} && typeof ${accessor} === 'object' && ${accessor}.constructor === Object`
break
case 'array':
condition = 'Array.isArray(value)'
condition = `Array.isArray(${accessor})`
break

@@ -711,4 +827,5 @@ default:

code += `
${statement} (${input} === null)
${statement} (${input} === null) {
${nestedResult}
}
`

@@ -728,4 +845,5 @@ break

)
)
) {
${nestedResult}
}
`

@@ -736,4 +854,5 @@ break

code += `
${statement}(Array.isArray(${input}))
${statement}(Array.isArray(${input})) {
${nestedResult}
}
`

@@ -744,4 +863,5 @@ break

code += `
${statement}(Number.isInteger(${input}) || ${input} === null)
${statement}(Number.isInteger(${input}) || ${input} === null) {
${nestedResult}
}
`

@@ -752,4 +872,5 @@ break

code += `
${statement}(typeof ${input} === "${type}" || ${input} === null)
${statement}(typeof ${input} === "${type}" || ${input} === null) {
${nestedResult}
}
`

@@ -760,8 +881,4 @@ break

})
let schemaRef = location.getSchemaRef()
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '')
}
code += `
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
else throw new TypeError(\`The value of '${getSafeSchemaRef(context, location)}' does not match schema definition.\`)
`

@@ -812,8 +929,6 @@

case 'object': {
const funcName = buildObject(context, location)
return `json += ${funcName}(${input})`
return buildObject(context, location, input)
}
case 'array': {
const funcName = buildArray(context, location)
return `json += ${funcName}(${input})`
return buildArray(context, location, input)
}

@@ -827,2 +942,88 @@ case undefined:

function detectRecursiveSchemas (context, location) {
const pathStack = new Set()
function traverse (location) {
const schema = location.schema
if (typeof schema !== 'object' || schema === null) return
const schemaId = location.schemaId || ''
const jsonPointer = location.jsonPointer || ''
const fullPath = `${schemaId}#${jsonPointer}`
if (pathStack.has(fullPath)) {
// Mark all nodes in the current path that are part of the cycle
let inCycle = false
for (const p of pathStack) {
if (p === fullPath) inCycle = true
if (inCycle) context.recursivePaths.add(p)
}
context.recursivePaths.add(fullPath)
return
}
pathStack.add(fullPath)
if (schema.$ref) {
try {
const res = resolveRef(context, location)
traverse(res)
} catch (err) {
// Validation will handle missing refs later
}
}
if (schema.properties) {
const propertiesLocation = location.getPropertyLocation('properties')
for (const key in schema.properties) {
traverse(propertiesLocation.getPropertyLocation(key))
}
}
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
traverse(location.getPropertyLocation('additionalProperties'))
}
if (schema.patternProperties) {
const patternPropertiesLocation = location.getPropertyLocation('patternProperties')
for (const key in schema.patternProperties) {
traverse(patternPropertiesLocation.getPropertyLocation(key))
}
}
if (schema.items) {
const itemsLocation = location.getPropertyLocation('items')
if (Array.isArray(schema.items)) {
for (let i = 0; i < schema.items.length; i++) {
traverse(itemsLocation.getPropertyLocation(i))
}
} else {
traverse(itemsLocation)
}
}
if (schema.additionalItems && typeof schema.additionalItems === 'object') {
traverse(location.getPropertyLocation('additionalItems'))
}
if (schema.oneOf) {
const oneOfLocation = location.getPropertyLocation('oneOf')
for (let i = 0; i < schema.oneOf.length; i++) {
traverse(oneOfLocation.getPropertyLocation(i))
}
}
if (schema.anyOf) {
const anyOfLocation = location.getPropertyLocation('anyOf')
for (let i = 0; i < schema.anyOf.length; i++) {
traverse(anyOfLocation.getPropertyLocation(i))
}
}
if (schema.allOf) {
const allOfLocation = location.getPropertyLocation('allOf')
for (let i = 0; i < schema.allOf.length; i++) {
traverse(allOfLocation.getPropertyLocation(i))
}
}
if (schema.then) traverse(location.getPropertyLocation('then'))
if (schema.else) traverse(location.getPropertyLocation('else'))
pathStack.delete(fullPath)
}
traverse(location)
}
function buildConstSerializer (location, input) {

@@ -877,3 +1078,3 @@ const schema = location.schema

const allOfsLocation = location.getPropertyLocation('allOf')
for (let i = 0; i < allOf.length; i++) {
for (let i = 0, allOfLength = allOf.length; i < allOfLength; i++) {
locations.push(allOfsLocation.getPropertyLocation(i))

@@ -903,3 +1104,3 @@ }

for (let index = 0; index < oneOfs.length; index++) {
for (let index = 0, oneOfsLength = oneOfs.length; index < oneOfsLength; index++) {
const optionLocation = oneOfsLocation.getPropertyLocation(index)

@@ -924,15 +1125,12 @@ const optionSchema = optionLocation.schema

const schemaRef = optionLocation.getSchemaRef()
code += `
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input}))
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input})) {
${nestedResult}
}
`
}
let schemaRef = location.getSchemaRef()
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '')
}
code += `
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
else throw new TypeError(\`The value of '${getSafeSchemaRef(context, location)}' does not match schema definition.\`)
`

@@ -939,0 +1137,0 @@

@@ -24,4 +24,4 @@ 'use strict'

errors: false,
validate: (_type, date) => {
return date instanceof Date
validate: (_type, data) => {
return data && typeof data.toJSON === 'function'
}

@@ -55,4 +55,6 @@ })

// Ajv does not support js date format. In order to properly validate objects containing a date,
// it needs to replace all occurrences of the string date format with a custom keyword fjs_type.
// Ajv does not natively support JavaScript objects like Date or other types
// that rely on a custom .toJSON() representation. To properly validate schemas
// that may contain such objects (e.g. Date, ObjectId, etc.), we replace all
// occurrences of the string type with a custom keyword fjs_type
// (see https://github.com/fastify/fast-json-stringify/pull/441)

@@ -59,0 +61,0 @@ convertSchemaToAjvFormat (schema) {

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

@@ -9,6 +9,6 @@ "main": "index.js",

"scripts": {
"bench": "node ./benchmark/bench.js",
"bench": "node --expose-gc ./benchmark/bench.js",
"bench:cmp": "node ./benchmark/bench-cmp-branch.js",
"bench:cmp:ci": "node ./benchmark/bench-cmp-branch.js --ci",
"benchmark": "node ./benchmark/bench-cmp-lib.js",
"benchmark": "node --expose-gc ./benchmark/bench-cmp-lib.js",
"lint": "eslint",

@@ -67,3 +67,2 @@ "lint:fix": "eslint --fix",

"@sinclair/typebox": "^0.34.3",
"benchmark": "^2.1.4",
"c8": "^10.1.2",

@@ -78,2 +77,3 @@ "cli-select": "^1.1.2",

"simple-git": "^3.23.0",
"tinybench": "^5.0.1",
"tsd": "^0.32.0",

@@ -80,0 +80,0 @@ "webpack": "^5.90.3"

@@ -10,3 +10,2 @@ # fast-json-stringify

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`.

@@ -13,0 +12,0 @@