Skip to content

Commit

Permalink
fix: deref schema without root
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-tymoshenko committed Nov 12, 2023
1 parent f936bed commit 3dcab1e
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 38 deletions.
89 changes: 51 additions & 38 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,41 @@ class RefResolver {
this.#cloneSchemaWithoutRefs = opts.cloneSchemaWithoutRefs ?? false
}

addSchema (schema, schemaId) {
if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {
// Schema has an $id that is not an anchor
schemaId = schema.$id
} else {
// Schema has no $id or $id is an anchor
this.#insertSchemaBySchemaId(schema, schemaId)
addSchema (schema, rootSchemaId, isRootSchema = true) {
if (isRootSchema) {
if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {
// Schema has an $id that is not an anchor
rootSchemaId = schema.$id
} else {
// Schema has no $id or $id is an anchor
this.#insertSchemaBySchemaId(schema, rootSchemaId)
}
}

const schemaId = schema.$id
if (schemaId !== undefined && typeof schemaId === 'string') {
if (schemaId.charAt(0) === '#') {
this.#insertSchemaByAnchor(schema, rootSchemaId, schemaId)
} else {
this.#insertSchemaBySchemaId(schema, schemaId)
rootSchemaId = schemaId
}
}

const ref = schema.$ref
if (ref !== undefined && typeof ref === 'string') {
const { refSchemaId, refJsonPointer } = this.#parseSchemaRef(ref, rootSchemaId)
this.#schemas[rootSchemaId].refs.push({
schemaId: refSchemaId,
jsonPointer: refJsonPointer
})
}

for (const key in schema) {
if (typeof schema[key] === 'object' && schema[key] !== null) {
this.addSchema(schema[key], rootSchemaId, false)
}
}
this.#addSchema(schema, schemaId)
}

getSchema (schemaId, jsonPointer = '#') {
Expand Down Expand Up @@ -60,7 +86,11 @@ class RefResolver {

for (const ref of schema.refs) {
const dependencySchemaId = ref.schemaId
if (dependencies[dependencySchemaId] !== undefined) continue
if (
dependencySchemaId === schemaId ||
dependencies[dependencySchemaId] !== undefined
) continue

dependencies[dependencySchemaId] = this.getSchema(dependencySchemaId)
this.getSchemaDependencies(dependencySchemaId, dependencies)
}
Expand All @@ -84,12 +114,12 @@ class RefResolver {
}

const refs = []
this.#addDerefSchema(schema.schema, schemaId, refs)
this.#addDerefSchema(schema.schema, schemaId, true, refs)

const dependencies = this.getSchemaDependencies(schemaId)
for (const schemaId in dependencies) {
const schema = dependencies[schemaId]
this.#addDerefSchema(schema, schemaId, refs)
this.#addDerefSchema(schema, schemaId, true, refs)
}

for (const ref of refs) {
Expand Down Expand Up @@ -140,35 +170,18 @@ class RefResolver {
}
}

#addSchema (schema, rootSchemaId) {
const schemaId = schema.$id
if (schemaId !== undefined && typeof schemaId === 'string') {
if (schemaId.charAt(0) === '#') {
this.#insertSchemaByAnchor(schema, rootSchemaId, schemaId)
} else {
this.#insertSchemaBySchemaId(schema, schemaId)
rootSchemaId = schemaId
}
}

const ref = schema.$ref
if (ref !== undefined && typeof ref === 'string') {
const { refSchemaId, refJsonPointer } = this.#parseSchemaRef(ref, rootSchemaId)
this.#schemas[rootSchemaId].refs.push({
schemaId: refSchemaId,
jsonPointer: refJsonPointer
})
}
#addDerefSchema (schema, rootSchemaId, isRootSchema, refs = []) {
const derefSchema = Array.isArray(schema) ? [...schema] : { ...schema }

for (const key in schema) {
if (typeof schema[key] === 'object' && schema[key] !== null) {
this.#addSchema(schema[key], rootSchemaId)
if (isRootSchema) {
if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {
// Schema has an $id that is not an anchor
rootSchemaId = schema.$id
} else {
// Schema has no $id or $id is an anchor
this.#insertDerefSchemaBySchemaId(derefSchema, rootSchemaId)
}
}
}

#addDerefSchema (schema, rootSchemaId, refs = []) {
const derefSchema = Array.isArray(schema) ? [...schema] : { ...schema }

const schemaId = derefSchema.$id
if (schemaId !== undefined && typeof schemaId === 'string') {
Expand All @@ -191,7 +204,7 @@ class RefResolver {
for (const key in derefSchema) {
const value = derefSchema[key]
if (typeof value === 'object' && value !== null) {
derefSchema[key] = this.#addDerefSchema(value, rootSchemaId, refs)
derefSchema[key] = this.#addDerefSchema(value, rootSchemaId, false, refs)
}
}

Expand Down
51 changes: 51 additions & 0 deletions test/deref-schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,54 @@ test('should throw if target ref schema is not found', () => {
)
}
})

test('should deref schema without root $id', () => {
const refResolver = new RefResolver()

const schemaId = 'schemaId1'
const schema = {
type: 'object',
definitions: {
id1: {
type: 'object',
properties: {
id1: {
type: 'integer'
}
}
}
},
allOf: [
{
$ref: '#/definitions/id1'
}
]
}

refResolver.addSchema(schema, schemaId)
const derefSchema = refResolver.getDerefSchema(schemaId)

assert.deepStrictEqual(derefSchema, {
type: 'object',
definitions: {
id1: {
type: 'object',
properties: {
id1: {
type: 'integer'
}
}
}
},
allOf: [
{
type: 'object',
properties: {
id1: {
type: 'integer'
}
}
}
]
})
})

0 comments on commit 3dcab1e

Please sign in to comment.