Skip to content

Commit

Permalink
fix: track schema dependecies (#556)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-tymoshenko committed Nov 5, 2022
1 parent 182a69b commit e2b6ef4
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 12 deletions.
13 changes: 6 additions & 7 deletions index.js
Expand Up @@ -56,11 +56,7 @@ function resolveRef (location, ref) {
throw new Error(`Cannot find reference "${ref}"`)
}

if (location.isValidated) {
validatorSchemasIds.add(schemaId)
}

const newLocation = new Location(schema, schemaId, jsonPointer, location.isValidated)
const newLocation = new Location(schema, schemaId, jsonPointer)
if (schema.$ref !== undefined) {
return resolveRef(newLocation, schema.$ref)
}
Expand Down Expand Up @@ -137,6 +133,11 @@ function build (schema, options) {
for (const schemaId of validatorSchemasIds) {
const schema = refResolver.getSchema(schemaId)
validator.addSchema(schema, schemaId)

const dependencies = refResolver.getSchemaDependencies(schemaId)
for (const [schemaId, schema] of Object.entries(dependencies)) {
validator.addSchema(schema, schemaId)
}
}

const dependenciesName = ['validator', 'serializer', contextFunctionCode]
Expand Down Expand Up @@ -454,7 +455,6 @@ function mergeAllOfSchema (location, schema, mergedSchema) {
}

function addIfThenElse (location, input) {
location.isValidated = true
validatorSchemasIds.add(location.getSchemaId())

const schema = merge({}, location.schema)
Expand Down Expand Up @@ -840,7 +840,6 @@ function buildValue (location, input) {
let code = ''

if (type === undefined && (schema.anyOf || schema.oneOf)) {
location.isValidated = true
validatorSchemasIds.add(location.getSchemaId())

const type = schema.anyOf ? 'anyOf' : 'oneOf'
Expand Down
6 changes: 2 additions & 4 deletions lib/location.js
@@ -1,20 +1,18 @@
'use strict'

class Location {
constructor (schema, schemaId, jsonPointer = '#', isValidated = false) {
constructor (schema, schemaId, jsonPointer = '#') {
this.schema = schema
this.schemaId = schemaId
this.jsonPointer = jsonPointer
this.isValidated = isValidated
this.mergedSchemaId = null
}

getPropertyLocation (propertyName) {
const propertyLocation = new Location(
this.schema[propertyName],
this.schemaId,
this.jsonPointer + '/' + propertyName,
this.isValidated
this.jsonPointer + '/' + propertyName
)

if (this.mergedSchemaId !== null) {
Expand Down
22 changes: 21 additions & 1 deletion lib/ref-resolver.js
Expand Up @@ -28,14 +28,26 @@ class RefResolver {
return getDataByJSONPointer(schema.schema, jsonPointer)
}

getSchemaDependencies (schemaId, dependencies = {}) {
const schema = this.schemas[schemaId]

for (const dependencySchemaId of schema.dependencies) {
if (dependencies[dependencySchemaId] !== undefined) continue
dependencies[dependencySchemaId] = this.getSchema(dependencySchemaId)
this.getSchemaDependencies(dependencySchemaId, dependencies)
}

return dependencies
}

insertSchemaBySchemaId (schema, schemaId) {
if (
this.schemas[schemaId] !== undefined &&
!deepEqual(schema, this.schemas[schemaId].schema)
) {
throw new Error(`There is already another schema with id ${schemaId}`)
}
this.schemas[schemaId] = { schema, anchors: {} }
this.schemas[schemaId] = { schema, anchors: {}, dependencies: [] }
}

insertSchemaByAnchor (schema, schemaId, anchor) {
Expand All @@ -60,6 +72,14 @@ class RefResolver {
}
}

const ref = schema.$ref
if (ref !== undefined && typeof ref === 'string') {
if (ref.charAt(0) !== '#') {
const dependencySchemaId = ref.split('#')[0]
this.schemas[rootSchemaId].dependencies.push(dependencySchemaId)
}
}

for (const key in schema) {
if (typeof schema[key] === 'object' && schema[key] !== null) {
this.insertSchemaSubschemas(schema[key], rootSchemaId)
Expand Down
28 changes: 28 additions & 0 deletions test/anyof.test.js
Expand Up @@ -616,3 +616,31 @@ test('anyOf with a nested external schema', (t) => {
const stringify = build(schema, { schema: externalSchemas })
t.equal(stringify('foo'), '"foo"')
})

test('object with ref and validated properties', (t) => {
t.plan(1)

const externalSchemas = {
RefSchema: {
$id: 'RefSchema',
type: 'string'
}
}

const schema = {
$id: 'root',
type: 'object',
properties: {
id: {
anyOf: [
{ type: 'string' },
{ type: 'number' }
]
},
reference: { $ref: 'RefSchema' }
}
}

const stringify = build(schema, { schema: externalSchemas })
t.equal(stringify({ id: 1, reference: 'hi' }), '{"id":1,"reference":"hi"}')
})

0 comments on commit e2b6ef4

Please sign in to comment.