Socket
Socket
Sign inDemoInstall

fast-json-stringify

Package Overview
Dependencies
11
Maintainers
9
Versions
160
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 5.10.0 to 5.11.0

lib/merge-schemas.js

503

index.js

@@ -5,10 +5,9 @@ 'use strict'

const merge = require('@fastify/deepmerge')()
const clone = require('rfdc')({ proto: true })
const { RefResolver } = require('json-schema-ref-resolver')
const validate = require('./lib/schema-validator')
const Serializer = require('./lib/serializer')
const Validator = require('./lib/validator')
const Location = require('./lib/location')
const validate = require('./lib/schema-validator')
const mergeSchemas = require('./lib/merge-schemas')

@@ -32,6 +31,6 @@ const SINGLE_TICK = /'/g

const addComma = '!addComma && (addComma = true) || (json += \',\')'
let schemaIdCounter = 0
const mergedSchemaRef = Symbol('fjs-merged-schema-ref')
function isValidSchema (schema, name) {

@@ -51,3 +50,5 @@ if (!validate(schema)) {

function resolveRef (context, location, ref) {
function resolveRef (context, location) {
const ref = location.schema.$ref
let hashIndex = ref.indexOf('#')

@@ -58,3 +59,3 @@ if (hashIndex === -1) {

const schemaId = ref.slice(0, hashIndex) || location.getOriginSchemaId()
const schemaId = ref.slice(0, hashIndex) || location.schemaId
const jsonPointer = ref.slice(hashIndex) || '#'

@@ -69,3 +70,3 @@

if (schema.$ref !== undefined) {
return resolveRef(context, newLocation, schema.$ref)
return resolveRef(context, newLocation)
}

@@ -76,2 +77,7 @@

function getMergedLocation (context, mergedSchemaId) {
const mergedSchema = context.refResolver.getSchema(mergedSchemaId, '#')
return new Location(mergedSchema, mergedSchemaId, '#')
}
function getSchemaId (schema, rootSchemaId) {

@@ -94,3 +100,2 @@ if (schema.$id && schema.$id.charAt(0) !== '#') {

options,
wrapObjects: true,
refResolver: new RefResolver(),

@@ -265,3 +270,3 @@ rootSchemaId: schema.$id || `__fjs_root_${schemaIdCounter++}`,

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

@@ -325,91 +330,76 @@ const propertiesKeys = Object.keys(schema.properties || {})

function buildInnerObject (context, location) {
let code = ''
const schema = location.schema
const required = schema.required || []
const propertiesLocation = location.getPropertyLocation('properties')
const requiredProperties = schema.required || []
const requiredWithDefault = []
const requiredWithoutDefault = []
if (schema.properties) {
for (const key of Object.keys(schema.properties)) {
if (required.indexOf(key) === -1) {
continue
}
let propertyLocation = propertiesLocation.getPropertyLocation(key)
if (propertyLocation.schema.$ref) {
propertyLocation = resolveRef(context, location, propertyLocation.schema.$ref)
}
// Should serialize required properties first
const propertiesKeys = Object.keys(schema.properties || {}).sort(
(key1, key2) => {
const required1 = requiredProperties.includes(key1)
const required2 = requiredProperties.includes(key2)
return required1 === required2 ? 0 : required1 ? -1 : 1
}
)
const hasRequiredProperties = requiredProperties.includes(propertiesKeys[0])
const sanitizedKey = JSON.stringify(key)
let code = ''
// Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
// see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
const defaultValue = propertyLocation.schema.default
if (defaultValue === undefined) {
code += `if (obj[${sanitizedKey}] === undefined) throw new Error('${sanitizedKey} is required!')\n`
requiredWithoutDefault.push(key)
}
requiredWithDefault.push(key)
for (const key of requiredProperties) {
if (!propertiesKeys.includes(key)) {
code += `if (obj['${key}'] === undefined) throw new Error('"${key}" is required!')\n`
}
}
// handle extraneous required fields
for (const requiredProperty of required) {
if (requiredWithDefault.indexOf(requiredProperty) !== -1) continue
code += `if (obj['${requiredProperty}'] === undefined) throw new Error('"${requiredProperty}" is required!')\n`
code += 'let json = \'{\'\n'
let addComma = ''
if (!hasRequiredProperties) {
code += 'let addComma = false\n'
addComma = '!addComma && (addComma = true) || (json += \',\')'
}
code += `
let addComma = false
let json = '${context.wrapObjects ? '{' : ''}'
`
const wrapObjects = context.wrapObjects
context.wrapObjects = true
for (const key of propertiesKeys) {
let propertyLocation = propertiesLocation.getPropertyLocation(key)
if (propertyLocation.schema.$ref) {
propertyLocation = resolveRef(context, propertyLocation)
}
if (schema.properties) {
for (const key of Object.keys(schema.properties)) {
let propertyLocation = propertiesLocation.getPropertyLocation(key)
if (propertyLocation.schema.$ref) {
propertyLocation = resolveRef(context, location, propertyLocation.schema.$ref)
}
const sanitizedKey = JSON.stringify(key)
const defaultValue = propertyLocation.schema.default
const isRequired = requiredProperties.includes(key)
const sanitizedKey = JSON.stringify(key)
if (requiredWithoutDefault.indexOf(key) !== -1) {
code += `
code += `
if (obj[${sanitizedKey}] !== undefined) {
${addComma}
json += ${JSON.stringify(sanitizedKey + ':')}
${buildValue(context, propertyLocation, `obj[${sanitizedKey}]`)}
}`
if (defaultValue !== undefined) {
code += ` else {
${addComma}
json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
}
`
} else {
// Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
// see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
code += `
if (obj[${sanitizedKey}] !== undefined) {
${addComma}
json += ${JSON.stringify(sanitizedKey + ':')}
${buildValue(context, propertyLocation, `obj[${sanitizedKey}]`)}
}
`
const defaultValue = propertyLocation.schema.default
if (defaultValue !== undefined) {
code += `
else {
${addComma}
json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
}
`
}
} else if (isRequired) {
code += ` else {
throw new Error('${sanitizedKey} is required!')
}
`
} else {
code += '\n'
}
if (hasRequiredProperties) {
addComma = 'json += \',\''
}
}
if (schema.patternProperties || schema.additionalProperties) {
code += buildExtraObjectPropertiesSerializer(context, location)
code += buildExtraObjectPropertiesSerializer(context, location, addComma)
}
context.wrapObjects = wrapObjects
code += `
return json${context.wrapObjects ? ' + \'}\'' : ''}
return json + '}'
`

@@ -419,130 +409,57 @@ return code

function mergeAllOfSchema (context, location, schema, mergedSchema) {
const allOfLocation = location.getPropertyLocation('allOf')
for (let i = 0; i < schema.allOf.length; i++) {
let allOfSchema = schema.allOf[i]
if (allOfSchema.$ref) {
const allOfSchemaLocation = allOfLocation.getPropertyLocation(i)
allOfSchema = resolveRef(context, allOfSchemaLocation, allOfSchema.$ref).schema
function mergeLocations (context, mergedSchemaId, mergedLocations) {
for (let i = 0; i < mergedLocations.length; i++) {
const location = mergedLocations[i]
const schema = location.schema
if (schema.$ref) {
mergedLocations[i] = resolveRef(context, location)
}
}
let allOfSchemaType = allOfSchema.type
if (allOfSchemaType === undefined) {
allOfSchemaType = inferTypeByKeyword(allOfSchema)
}
const mergedSchemas = []
for (const location of mergedLocations) {
const schema = cloneOriginSchema(location.schema, location.schemaId)
delete schema.$id
if (allOfSchemaType !== undefined) {
if (
mergedSchema.type !== undefined &&
mergedSchema.type !== allOfSchemaType
) {
throw new Error('allOf schemas have different type values')
}
mergedSchema.type = allOfSchemaType
}
mergedSchemas.push(schema)
}
if (allOfSchema.format !== undefined) {
if (
mergedSchema.format !== undefined &&
mergedSchema.format !== allOfSchema.format
) {
throw new Error('allOf schemas have different format values')
}
mergedSchema.format = allOfSchema.format
}
const mergedSchema = mergeSchemas(mergedSchemas)
const mergedLocation = new Location(mergedSchema, mergedSchemaId)
if (allOfSchema.nullable !== undefined) {
if (
mergedSchema.nullable !== undefined &&
mergedSchema.nullable !== allOfSchema.nullable
) {
throw new Error('allOf schemas have different nullable values')
}
mergedSchema.nullable = allOfSchema.nullable
}
context.refResolver.addSchema(mergedSchema, mergedSchemaId)
return mergedLocation
}
if (allOfSchema.properties !== undefined) {
if (mergedSchema.properties === undefined) {
mergedSchema.properties = {}
}
Object.assign(mergedSchema.properties, allOfSchema.properties)
}
function cloneOriginSchema (schema, schemaId) {
const clonedSchema = Array.isArray(schema) ? [] : {}
if (allOfSchema.additionalProperties !== undefined) {
if (mergedSchema.additionalProperties === undefined) {
mergedSchema.additionalProperties = {}
}
Object.assign(mergedSchema.additionalProperties, allOfSchema.additionalProperties)
}
if (
schema.$id !== undefined &&
schema.$id.charAt(0) !== '#'
) {
schemaId = schema.$id
}
if (allOfSchema.patternProperties !== undefined) {
if (mergedSchema.patternProperties === undefined) {
mergedSchema.patternProperties = {}
}
Object.assign(mergedSchema.patternProperties, allOfSchema.patternProperties)
}
if (schema[mergedSchemaRef]) {
clonedSchema[mergedSchemaRef] = schema[mergedSchemaRef]
}
if (allOfSchema.required !== undefined) {
if (mergedSchema.required === undefined) {
mergedSchema.required = []
}
mergedSchema.required.push(...allOfSchema.required)
}
for (const key in schema) {
let value = schema[key]
if (allOfSchema.oneOf !== undefined) {
if (mergedSchema.oneOf === undefined) {
mergedSchema.oneOf = []
}
mergedSchema.oneOf.push(...allOfSchema.oneOf)
if (key === '$ref' && value.charAt(0) === '#') {
value = schemaId + value
}
if (allOfSchema.anyOf !== undefined) {
if (mergedSchema.anyOf === undefined) {
mergedSchema.anyOf = []
}
mergedSchema.anyOf.push(...allOfSchema.anyOf)
if (typeof value === 'object' && value !== null) {
value = cloneOriginSchema(value, schemaId)
}
if (allOfSchema.allOf !== undefined) {
mergeAllOfSchema(context, location, allOfSchema, mergedSchema)
}
clonedSchema[key] = value
}
delete mergedSchema.allOf
mergedSchema.$id = `__fjs_merged_${schemaIdCounter++}`
context.refResolver.addSchema(mergedSchema)
location.addMergedSchema(mergedSchema, mergedSchema.$id)
return clonedSchema
}
function addIfThenElse (context, location, input) {
context.validatorSchemasIds.add(location.getSchemaId())
const schema = merge({}, location.schema)
const thenSchema = schema.then
const elseSchema = schema.else || { additionalProperties: true }
delete schema.if
delete schema.then
delete schema.else
const ifLocation = location.getPropertyLocation('if')
const ifSchemaRef = ifLocation.getSchemaRef()
const thenLocation = location.getPropertyLocation('then')
thenLocation.schema = merge(schema, thenSchema)
const elseLocation = location.getPropertyLocation('else')
elseLocation.schema = merge(schema, elseSchema)
return `
if (validator.validate("${ifSchemaRef}", ${input})) {
${buildValue(context, thenLocation, input)}
} else {
${buildValue(context, elseLocation, input)}
}
`
}
function toJSON (variableName) {

@@ -595,3 +512,3 @@ return `(${variableName} && typeof ${variableName}.toJSON === 'function')

if (itemsLocation.schema.$ref) {
itemsLocation = resolveRef(context, itemsLocation, itemsLocation.schema.$ref)
itemsLocation = resolveRef(context, itemsLocation)
}

@@ -874,77 +791,189 @@

function buildValue (context, location, input) {
let schema = location.schema
function buildAllOf (context, location, input) {
const schema = location.schema
if (typeof schema === 'boolean') {
return `json += JSON.stringify(${input})`
let mergedSchemaId = schema[mergedSchemaRef]
if (mergedSchemaId) {
const mergedLocation = getMergedLocation(context, mergedSchemaId)
return buildValue(context, mergedLocation, input)
}
if (schema.$ref) {
location = resolveRef(context, location, schema.$ref)
schema = location.schema
mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
schema[mergedSchemaRef] = mergedSchemaId
const { allOf, ...schemaWithoutAllOf } = location.schema
const locations = [
new Location(
schemaWithoutAllOf,
location.schemaId,
location.jsonPointer
)
]
const allOfsLocation = location.getPropertyLocation('allOf')
for (let i = 0; i < allOf.length; i++) {
locations.push(allOfsLocation.getPropertyLocation(i))
}
if (schema.type === undefined) {
const inferredType = inferTypeByKeyword(schema)
if (inferredType) {
schema.type = inferredType
const mergedLocation = mergeLocations(context, mergedSchemaId, locations)
return buildValue(context, mergedLocation, input)
}
function buildOneOf (context, location, input) {
context.validatorSchemasIds.add(location.schemaId)
const schema = location.schema
const type = schema.anyOf ? 'anyOf' : 'oneOf'
const { [type]: oneOfs, ...schemaWithoutAnyOf } = location.schema
const locationWithoutOneOf = new Location(
schemaWithoutAnyOf,
location.schemaId,
location.jsonPointer
)
const oneOfsLocation = location.getPropertyLocation(type)
let code = ''
for (let index = 0; index < oneOfs.length; index++) {
const optionLocation = oneOfsLocation.getPropertyLocation(index)
const optionSchema = optionLocation.schema
let mergedSchemaId = optionSchema[mergedSchemaRef]
let mergedLocation = null
if (mergedSchemaId) {
mergedLocation = getMergedLocation(context, mergedSchemaId)
} else {
mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
optionSchema[mergedSchemaRef] = mergedSchemaId
mergedLocation = mergeLocations(context, mergedSchemaId, [
locationWithoutOneOf,
optionLocation
])
}
const nestedResult = buildValue(context, mergedLocation, input)
const schemaRef = optionLocation.getSchemaRef()
code += `
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input}))
${nestedResult}
`
}
if (schema.if && schema.then) {
return addIfThenElse(context, location, input)
let schemaRef = location.getSchemaRef()
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '')
}
if (schema.allOf) {
mergeAllOfSchema(context, location, schema, clone(schema))
schema = location.schema
code += `
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
`
return code
}
function buildIfThenElse (context, location, input) {
context.validatorSchemasIds.add(location.schemaId)
const {
if: ifSchema,
then: thenSchema,
else: elseSchema,
...schemaWithoutIfThenElse
} = location.schema
const rootLocation = new Location(
schemaWithoutIfThenElse,
location.schemaId,
location.jsonPointer
)
const ifLocation = location.getPropertyLocation('if')
const ifSchemaRef = ifLocation.getSchemaRef()
const thenLocation = location.getPropertyLocation('then')
let thenMergedSchemaId = thenSchema[mergedSchemaRef]
let thenMergedLocation = null
if (thenMergedSchemaId) {
thenMergedLocation = getMergedLocation(context, thenMergedSchemaId)
} else {
thenMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
thenSchema[mergedSchemaRef] = thenMergedSchemaId
thenMergedLocation = mergeLocations(context, thenMergedSchemaId, [
rootLocation,
thenLocation
])
}
const type = schema.type
if (!elseSchema) {
return `
if (validator.validate("${ifSchemaRef}", ${input})) {
${buildValue(context, thenMergedLocation, input)}
} else {
${buildValue(context, rootLocation, input)}
}
`
}
let code = ''
const elseLocation = location.getPropertyLocation('else')
let elseMergedSchemaId = elseSchema[mergedSchemaRef]
let elseMergedLocation = null
if (elseMergedSchemaId) {
elseMergedLocation = getMergedLocation(context, elseMergedSchemaId)
} else {
elseMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
elseSchema[mergedSchemaRef] = elseMergedSchemaId
if ((type === undefined || type === 'object') && (schema.anyOf || schema.oneOf)) {
context.validatorSchemasIds.add(location.getSchemaId())
elseMergedLocation = mergeLocations(context, elseMergedSchemaId, [
rootLocation,
elseLocation
])
}
if (schema.type === 'object') {
context.wrapObjects = false
const funcName = buildObject(context, location)
code += `
json += '{'
json += ${funcName}(${input})
json += ','
`
return `
if (validator.validate("${ifSchemaRef}", ${input})) {
${buildValue(context, thenMergedLocation, input)}
} else {
${buildValue(context, elseMergedLocation, input)}
}
`
}
const type = schema.anyOf ? 'anyOf' : 'oneOf'
const anyOfLocation = location.getPropertyLocation(type)
function buildValue (context, location, input) {
let schema = location.schema
for (let index = 0; index < location.schema[type].length; index++) {
const optionLocation = anyOfLocation.getPropertyLocation(index)
const schemaRef = optionLocation.getSchemaRef()
const nestedResult = buildValue(context, optionLocation, input)
code += `
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input}))
${nestedResult}
`
}
if (typeof schema === 'boolean') {
return `json += JSON.stringify(${input})`
}
let schemaRef = location.getSchemaRef()
if (schemaRef.startsWith(context.rootSchemaId)) {
schemaRef = schemaRef.replace(context.rootSchemaId, '')
}
if (schema.$ref) {
location = resolveRef(context, location)
schema = location.schema
}
code += `
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
`
if (schema.type === 'object') {
code += `
json += '}'
`
context.wrapObjects = true
if (schema.allOf) {
return buildAllOf(context, location, input)
}
if (schema.anyOf || schema.oneOf) {
return buildOneOf(context, location, input)
}
if (schema.if && schema.then) {
return buildIfThenElse(context, location, input)
}
if (schema.type === undefined) {
const inferredType = inferTypeByKeyword(schema)
if (inferredType) {
schema.type = inferredType
}
return code
}
let code = ''
const type = schema.type
const nullable = schema.nullable === true

@@ -951,0 +980,0 @@ if (nullable) {

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

this.jsonPointer = jsonPointer
this.mergedSchemaId = null
}

@@ -18,38 +17,10 @@

)
if (this.mergedSchemaId !== null) {
propertyLocation.addMergedSchema(
this.schema[propertyName],
this.mergedSchemaId,
this.jsonPointer + '/' + propertyName
)
}
return propertyLocation
}
// Use this method to get current schema location.
// Use it when you need to create reference to the current location.
getSchemaId () {
return this.mergedSchemaId || this.schemaId
}
// Use this method to get original schema id for resolving user schema $refs
// Don't join it with a JSON pointer to get the current location.
getOriginSchemaId () {
return this.schemaId
}
getSchemaRef () {
const schemaId = this.getSchemaId()
return schemaId + this.jsonPointer
return this.schemaId + this.jsonPointer
}
addMergedSchema (mergedSchema, schemaId, jsonPointer = '#') {
this.schema = mergedSchema
this.mergedSchemaId = schemaId
this.jsonPointer = jsonPointer
}
}
module.exports = Location
{
"name": "fast-json-stringify",
"version": "5.10.0",
"version": "5.11.0",
"description": "Stringify your JSON at max speed",

@@ -49,3 +49,3 @@ "main": "index.js",

"tap": "^16.0.1",
"tsd": "^0.29.0",
"tsd": "^0.30.3",
"webpack": "^5.40.0",

@@ -55,3 +55,2 @@ "fast-json-stringify": "."

"dependencies": {
"@fastify/deepmerge": "^1.0.0",
"ajv": "^8.10.0",

@@ -62,3 +61,4 @@ "ajv-formats": "^2.1.1",

"rfdc": "^1.2.0",
"json-schema-ref-resolver": "^1.0.1"
"json-schema-ref-resolver": "^1.0.1",
"@fastify/merge-json-schemas": "^0.1.0"
},

@@ -65,0 +65,0 @@ "standard": {

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

tag: 'otherString'
}), '{"name":"string","tag":"otherString","id":1}')
}), '{"name":"string","id":1,"tag":"otherString"}')
})

@@ -557,4 +557,56 @@

test('allOf: multiple nested $ref properties', (t) => {
t.plan(2)
const externalSchema1 = {
$id: 'externalSchema1',
oneOf: [
{ $ref: '#/definitions/id1' }
],
definitions: {
id1: {
type: 'object',
properties: {
id1: {
type: 'integer'
}
},
additionalProperties: false
}
}
}
const externalSchema2 = {
$id: 'externalSchema2',
oneOf: [
{ $ref: '#/definitions/id2' }
],
definitions: {
id2: {
type: 'object',
properties: {
id2: {
type: 'integer'
}
},
additionalProperties: false
}
}
}
const schema = {
anyOf: [
{ $ref: 'externalSchema1' },
{ $ref: 'externalSchema2' }
]
}
const stringify = build(schema, { schema: [externalSchema1, externalSchema2] })
t.equal(stringify({ id1: 1 }), JSON.stringify({ id1: 1 }))
t.equal(stringify({ id2: 2 }), JSON.stringify({ id2: 2 }))
})
test('allOf: throw Error if types mismatch ', (t) => {
t.plan(1)
t.plan(3)

@@ -567,7 +619,14 @@ const schema = {

}
t.throws(() => build(schema), new Error('allOf schemas have different type values'))
try {
build(schema)
t.fail('should throw the MergeError')
} catch (error) {
t.ok(error instanceof Error)
t.equal(error.message, 'Failed to merge "type" keyword schemas.')
t.same(error.schemas, [['string'], ['number']])
}
})
test('allOf: throw Error if format mismatch ', (t) => {
t.plan(1)
t.plan(3)

@@ -580,27 +639,85 @@ const schema = {

}
t.throws(() => build(schema), new Error('allOf schemas have different format values'))
try {
build(schema)
t.fail('should throw the MergeError')
} catch (error) {
t.ok(error instanceof Error)
t.equal(error.message, 'Failed to merge "format" keyword schemas.')
t.same(error.schemas, ['date', 'time'])
}
})
test('allOf: throw Error if nullable mismatch /1', (t) => {
test('recursive nested allOfs', (t) => {
t.plan(1)
const schema = {
allOf: [
{ nullable: true },
{ nullable: false }
]
type: 'object',
properties: {
foo: {
additionalProperties: false,
allOf: [{ $ref: '#' }]
}
}
}
t.throws(() => build(schema), new Error('allOf schemas have different nullable values'))
const data = { foo: {} }
const stringify = build(schema)
t.equal(stringify(data), JSON.stringify(data))
})
test('allOf: throw Error if nullable mismatch /2', (t) => {
test('recursive nested allOfs', (t) => {
t.plan(1)
const schema = {
allOf: [
{ nullable: false },
{ nullable: true }
]
type: 'object',
properties: {
foo: {
additionalProperties: false,
allOf: [{ allOf: [{ $ref: '#' }] }]
}
}
}
t.throws(() => build(schema), new Error('allOf schemas have different nullable values'))
const data = { foo: {} }
const stringify = build(schema)
t.equal(stringify(data), JSON.stringify(data))
})
test('external recursive allOfs', (t) => {
t.plan(1)
const externalSchema = {
type: 'object',
properties: {
foo: {
properties: {
bar: { type: 'string' }
},
allOf: [{ $ref: '#' }]
}
}
}
const schema = {
type: 'object',
properties: {
a: { $ref: 'externalSchema#/properties/foo' },
b: { $ref: 'externalSchema#/properties/foo' }
}
}
const data = {
a: {
foo: {},
bar: '42',
baz: 42
},
b: {
foo: {},
bar: '42',
baz: 42
}
}
const stringify = build(schema, { schema: { externalSchema } })
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
})

@@ -647,1 +647,122 @@ 'use strict'

})
test('anyOf required props', (t) => {
t.plan(3)
const schema = {
type: 'object',
properties: {
prop1: { type: 'string' },
prop2: { type: 'string' },
prop3: { type: 'string' }
},
required: ['prop1'],
anyOf: [{ required: ['prop2'] }, { required: ['prop3'] }]
}
const stringify = build(schema)
t.equal(stringify({ prop1: 'test', prop2: 'test2' }), '{"prop1":"test","prop2":"test2"}')
t.equal(stringify({ prop1: 'test', prop3: 'test3' }), '{"prop1":"test","prop3":"test3"}')
t.equal(stringify({ prop1: 'test', prop2: 'test2', prop3: 'test3' }), '{"prop1":"test","prop2":"test2","prop3":"test3"}')
})
test('anyOf required props', (t) => {
t.plan(3)
const schema = {
type: 'object',
properties: {
prop1: { type: 'string' }
},
anyOf: [
{
properties: {
prop2: { type: 'string' }
}
},
{
properties: {
prop3: { type: 'string' }
}
}
]
}
const stringify = build(schema)
t.equal(stringify({ prop1: 'test1' }), '{"prop1":"test1"}')
t.equal(stringify({ prop2: 'test2' }), '{"prop2":"test2"}')
t.equal(stringify({ prop1: 'test1', prop2: 'test2' }), '{"prop1":"test1","prop2":"test2"}')
})
test('recursive nested anyOfs', (t) => {
t.plan(1)
const schema = {
type: 'object',
properties: {
foo: {
additionalProperties: false,
anyOf: [{ $ref: '#' }]
}
}
}
const data = { foo: {} }
const stringify = build(schema)
t.equal(stringify(data), JSON.stringify(data))
})
test('recursive nested anyOfs', (t) => {
t.plan(1)
const schema = {
type: 'object',
properties: {
foo: {
additionalProperties: false,
anyOf: [{ anyOf: [{ $ref: '#' }] }]
}
}
}
const data = { foo: {} }
const stringify = build(schema)
t.equal(stringify(data), JSON.stringify(data))
})
test('external recursive anyOfs', (t) => {
t.plan(1)
const externalSchema = {
type: 'object',
properties: {
foo: {
properties: {
bar: { type: 'string' }
},
anyOf: [{ $ref: '#' }]
}
}
}
const schema = {
type: 'object',
properties: {
a: { $ref: 'externalSchema#/properties/foo' },
b: { $ref: 'externalSchema#/properties/foo' }
}
}
const data = {
a: {
foo: {},
bar: '42',
baz: 42
},
b: {
foo: {},
bar: '42',
baz: 42
}
}
const stringify = build(schema, { schema: { externalSchema } })
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
})

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

})
const noElseGreetingOutput = JSON.stringify({
kind: 'greeting',
foo: 'FOO',
bar: 42,
hi: 'HI',
hello: 45,
a: 'A',
b: 35
})
const noElseGreetingOutput = JSON.stringify({})

@@ -423,1 +415,58 @@ t.test('if-then-else', t => {

})
t.test('external recursive if/then/else', (t) => {
t.plan(1)
const externalSchema = {
type: 'object',
properties: {
base: { type: 'string' },
self: { $ref: 'externalSchema#' }
},
if: {
type: 'object',
properties: {
foo: { type: 'string', const: '41' }
}
},
then: {
type: 'object',
properties: {
bar: { type: 'string', const: '42' }
}
},
else: {
type: 'object',
properties: {
baz: { type: 'string', const: '43' }
}
}
}
const schema = {
type: 'object',
properties: {
a: { $ref: 'externalSchema#/properties/self' },
b: { $ref: 'externalSchema#/properties/self' }
}
}
const data = {
a: {
base: 'a',
foo: '41',
bar: '42',
baz: '43',
ignore: 'ignored'
},
b: {
base: 'b',
foo: 'not-41',
bar: '42',
baz: '43',
ignore: 'ignored'
}
}
const stringify = build(schema, { schema: { externalSchema } })
t.equal(stringify(data), '{"a":{"base":"a","bar":"42"},"b":{"base":"b","baz":"43"}}')
})

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

} catch (e) {
t.equal(e.message, '"num" is required!')
t.equal(e.message, '"key1" is required!')
t.pass()

@@ -136,7 +136,8 @@ }

stringify({
num: 42
key1: 42,
key2: 42
})
t.fail()
} catch (e) {
t.equal(e.message, '"key1" is required!')
t.equal(e.message, '"num" is required!')
t.pass()

@@ -143,0 +144,0 @@ }

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc