Skip to content

Commit

Permalink
fix: merged schemas caching
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-tymoshenko authored and mcollina committed Feb 5, 2024
1 parent 1af56e3 commit d55d3be
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 16 deletions.
32 changes: 16 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ const validLargeArrayMechanisms = [

let schemaIdCounter = 0

const mergedSchemaRef = Symbol('fjs-merged-schema-ref')

function isValidSchema (schema, name) {
if (!validate(schema)) {
if (name) {
Expand Down Expand Up @@ -93,7 +91,8 @@ function build (schema, options) {
options,
refResolver: new RefResolver(),
rootSchemaId: schema.$id || `__fjs_root_${schemaIdCounter++}`,
validatorSchemasIds: new Set()
validatorSchemasIds: new Set(),
mergedSchemasIds: new Map()
}

const schemaId = getSchemaId(schema, context.rootSchemaId)
Expand Down Expand Up @@ -408,7 +407,7 @@ function mergeLocations (context, mergedSchemaId, mergedLocations) {

const mergedSchemas = []
for (const location of mergedLocations) {
const schema = cloneOriginSchema(location.schema, location.schemaId)
const schema = cloneOriginSchema(context, location.schema, location.schemaId)
delete schema.$id

mergedSchemas.push(schema)
Expand All @@ -421,7 +420,7 @@ function mergeLocations (context, mergedSchemaId, mergedLocations) {
return mergedLocation
}

function cloneOriginSchema (schema, schemaId) {
function cloneOriginSchema (context, schema, schemaId) {
const clonedSchema = Array.isArray(schema) ? [] : {}

if (
Expand All @@ -431,8 +430,9 @@ function cloneOriginSchema (schema, schemaId) {
schemaId = schema.$id
}

if (schema[mergedSchemaRef]) {
clonedSchema[mergedSchemaRef] = schema[mergedSchemaRef]
const mergedSchemaRef = context.mergedSchemasIds.get(schema)
if (mergedSchemaRef) {
context.mergedSchemasIds.set(clonedSchema, mergedSchemaRef)
}

for (const key in schema) {
Expand All @@ -443,7 +443,7 @@ function cloneOriginSchema (schema, schemaId) {
}

if (typeof value === 'object' && value !== null) {
value = cloneOriginSchema(value, schemaId)
value = cloneOriginSchema(context, value, schemaId)
}

clonedSchema[key] = value
Expand Down Expand Up @@ -780,14 +780,14 @@ function buildConstSerializer (location, input) {
function buildAllOf (context, location, input) {
const schema = location.schema

let mergedSchemaId = schema[mergedSchemaRef]
let mergedSchemaId = context.mergedSchemasIds.get(schema)
if (mergedSchemaId) {
const mergedLocation = getMergedLocation(context, mergedSchemaId)
return buildValue(context, mergedLocation, input)
}

mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
schema[mergedSchemaRef] = mergedSchemaId
context.mergedSchemasIds.set(schema, mergedSchemaId)

const { allOf, ...schemaWithoutAllOf } = location.schema
const locations = [
Expand Down Expand Up @@ -828,13 +828,13 @@ function buildOneOf (context, location, input) {
const optionLocation = oneOfsLocation.getPropertyLocation(index)
const optionSchema = optionLocation.schema

let mergedSchemaId = optionSchema[mergedSchemaRef]
let mergedSchemaId = context.mergedSchemasIds.get(optionSchema)
let mergedLocation = null
if (mergedSchemaId) {
mergedLocation = getMergedLocation(context, mergedSchemaId)
} else {
mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
optionSchema[mergedSchemaRef] = mergedSchemaId
context.mergedSchemasIds.set(optionSchema, mergedSchemaId)

mergedLocation = mergeLocations(context, mergedSchemaId, [
locationWithoutOneOf,
Expand Down Expand Up @@ -882,13 +882,13 @@ function buildIfThenElse (context, location, input) {
const ifSchemaRef = ifLocation.getSchemaRef()

const thenLocation = location.getPropertyLocation('then')
let thenMergedSchemaId = thenSchema[mergedSchemaRef]
let thenMergedSchemaId = context.mergedSchemasIds.get(thenSchema)
let thenMergedLocation = null
if (thenMergedSchemaId) {
thenMergedLocation = getMergedLocation(context, thenMergedSchemaId)
} else {
thenMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
thenSchema[mergedSchemaRef] = thenMergedSchemaId
context.mergedSchemasIds.set(thenSchema, thenMergedSchemaId)

thenMergedLocation = mergeLocations(context, thenMergedSchemaId, [
rootLocation,
Expand All @@ -907,13 +907,13 @@ function buildIfThenElse (context, location, input) {
}

const elseLocation = location.getPropertyLocation('else')
let elseMergedSchemaId = elseSchema[mergedSchemaRef]
let elseMergedSchemaId = context.mergedSchemasIds.get(elseSchema)
let elseMergedLocation = null
if (elseMergedSchemaId) {
elseMergedLocation = getMergedLocation(context, elseMergedSchemaId)
} else {
elseMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
elseSchema[mergedSchemaRef] = elseMergedSchemaId
context.mergedSchemasIds.set(elseSchema, elseMergedSchemaId)

elseMergedLocation = mergeLocations(context, elseMergedSchemaId, [
rootLocation,
Expand Down
27 changes: 27 additions & 0 deletions test/anyof.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,3 +765,30 @@ test('external recursive anyOfs', (t) => {
const stringify = build(schema, { schema: { externalSchema } })
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
})

test('should build merged schemas twice', (t) => {
t.plan(2)

const schema = {
type: 'object',
properties: {
enums: {
type: 'string',
anyOf: [
{ type: 'string', const: 'FOO' },
{ type: 'string', const: 'BAR' }
]
}
}
}

{
const stringify = build(schema)
t.equal(stringify({ enums: 'FOO' }), '{"enums":"FOO"}')
}

{
const stringify = build(schema)
t.equal(stringify({ enums: 'BAR' }), '{"enums":"BAR"}')
}
})

0 comments on commit d55d3be

Please sign in to comment.