From d26fe26a6c26c0ae9cda227e21b4509f85105c1d Mon Sep 17 00:00:00 2001 From: Polenkov Konstantin Date: Thu, 5 Dec 2024 18:03:30 +0500 Subject: [PATCH] fix(recursion): resolve infinite loop with recursive links --- src/dereferencer.ts | 1 + src/index.test.ts | 65 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/dereferencer.ts b/src/dereferencer.ts index 79d06cd..03ec752 100644 --- a/src/dereferencer.ts +++ b/src/dereferencer.ts @@ -157,6 +157,7 @@ export default class Dereferencer { const refProm = referenceResolver.resolve(ref, this.options.rootSchema); proms.push(refProm); fetched = await refProm as JSONSchema; + this.refCache[ref] = fetched } if (this.options.recursive === true && fetched !== true && fetched !== false && ref !== "#") { diff --git a/src/index.test.ts b/src/index.test.ts index 7423652..8e7b7a4 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,4 +1,3 @@ -import {inspect} from 'util'; import Dereferencer, { NonStringRefError } from "./index"; import { Properties, JSONSchemaObject, JSONSchema } from "@json-schema-tools/meta-schema"; @@ -169,6 +168,70 @@ describe("Dereferencer", () => { expect(oneOfs[0].properties.contains).toBe(dereffed); }); + it("does not get stuck on a recursive ", async () => { + expect.assertions(1); + const dereferencer = new Dereferencer({ + definitions: { + node: { + type: "object", + properties: { + name: { + type: "string" + }, + children: { + type: "array", + items: { + $ref: "#/definitions/node" + } + } + } + } + }, + type: "object", + properties: { + tree: { + title: "Recursive references", + $ref: "#/definitions/node" + } + } + }); + + const dereffed = await dereferencer.resolve(); + + + const recursiveChildren = { + type: 'array', + items: { + type: 'object', + properties: { + name: { + type: 'string' + }, + children: {} + } + }, + }; + recursiveChildren.items.properties.children = recursiveChildren + + const expected = { + type: "object", + properties: { + tree: { + title: "Recursive references", + type: "object", + properties: { + name: { + type: 'string' + }, + children: recursiveChildren + } + }, + } + } + + expect(dereffed).toStrictEqual(expected); + }); + it("can deal with root refs-to-ref as url, metaschema on master", async () => { expect.assertions(8); const dereferencer = new Dereferencer({