From a9fa9542d2b7dafb6497cb02a965b69b861b0fe6 Mon Sep 17 00:00:00 2001 From: Damir Date: Mon, 25 Dec 2023 22:37:45 +0600 Subject: [PATCH] fix #67: cycle references support --- package.json | 4 +- src/merge.ts | 6 +- src/normalize.ts | 4 +- src/resolvers/basic.ts | 2 +- src/resolvers/combinary.ts | 2 +- src/resolvers/items.ts | 2 +- src/resolvers/properties.ts | 2 +- src/rules/graphapi.ts | 2 +- src/rules/jsonschema.ts | 2 +- src/rules/openapi.ts | 2 +- src/types.ts | 2 +- src/utils.ts | 4 +- test/merge.cycleRefs.test.ts | 109 ++++++++++++++++++++++++++++++----- yarn.lock | 8 +-- 14 files changed, 114 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index 93e4bbc..32fdb08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "allof-merge", - "version": "0.6.1", + "version": "0.6.2", "description": "Simplify your JsonSchema by combining allOf safely.", "module": "dist/index.mjs", "main": "dist/index.cjs", @@ -84,6 +84,6 @@ "collectCoverage": true }, "dependencies": { - "json-crawl": "^0.4.2" + "json-crawl": "^0.5.1" } } diff --git a/src/merge.ts b/src/merge.ts index c3c5a56..63d59a3 100644 --- a/src/merge.ts +++ b/src/merge.ts @@ -1,6 +1,6 @@ import { JsonPath, SyncCloneHook, isObject, syncClone } from "json-crawl" -import { AllOfRef, MergeError, MergeOptions, MergeResolver, MergeRules } from "./types" +import type { AllOfRef, MergeError, MergeOptions, MergeResolver, MergeRules } from "./types" import { buildPointer, isAnyOfNode, isOneOfNode } from "./utils" import { mergeCombinarySibling } from "./resolvers/combinary" import { jsonSchemaMergeResolver } from "./resolvers" @@ -68,11 +68,11 @@ export const allOfResolverHook = (options?: MergeOptions): SyncCloneHook<{}> => // skip if not object if (!isObject(value) || Array.isArray(value)) { - return { value: value, exitHook } + return { exitHook } } // check if in current node expected allOf merge rule in rules - if (!isAllOfMergeRule(rules)) { return { value, exitHook } } + if (!isAllOfMergeRule(rules)) { return { exitHook } } const { allOf, ...sibling } = value diff --git a/src/normalize.ts b/src/normalize.ts index 7805312..845b00a 100644 --- a/src/normalize.ts +++ b/src/normalize.ts @@ -1,7 +1,7 @@ -import { JsonPath, isObject } from "json-crawl" +import { type JsonPath, isObject } from "json-crawl" import { buildPointer, isRefNode, parseRef, resolvePointer } from "./utils" -import { AllOfRef, NormalizeResponse } from "./types" +import type { AllOfRef, NormalizeResponse } from "./types" export const normalizeAllOfItems = (allOfItems: any[], jsonPath: JsonPath, source: any, allOfRefs: AllOfRef[]): NormalizeResponse => { const resolvedAllOfItems = [] diff --git a/src/resolvers/basic.ts b/src/resolvers/basic.ts index 7fe503c..a2056fe 100644 --- a/src/resolvers/basic.ts +++ b/src/resolvers/basic.ts @@ -1,6 +1,6 @@ import { calculateLCM, findCombinations, isEqual, mergeValues } from "../utils" import { getAllOfItemsMap } from "./jsonschema" -import { MergeResolver } from "../types" +import type { MergeResolver } from "../types" export const first: MergeResolver = ([a]) => a export const last: MergeResolver = (args) => args[args.length-1] diff --git a/src/resolvers/combinary.ts b/src/resolvers/combinary.ts index 904ef55..277357d 100644 --- a/src/resolvers/combinary.ts +++ b/src/resolvers/combinary.ts @@ -1,4 +1,4 @@ -import { AnyOfNode, MergeRule, OneOfNode } from "../types" +import type { AnyOfNode, MergeRule, OneOfNode } from "../types" import { popValues } from "../utils" export const mergeCombinarySibling = (value: AnyOfNode | OneOfNode, combinaryKey: "anyOf" | "oneOf", rule: MergeRule) => { diff --git a/src/resolvers/items.ts b/src/resolvers/items.ts index a8a89f3..82446d0 100644 --- a/src/resolvers/items.ts +++ b/src/resolvers/items.ts @@ -1,5 +1,5 @@ import { jsonSchemaMergeResolver } from "./jsonschema" -import { MergeResolver } from "../types" +import type { MergeResolver } from "../types" import { MapArray } from "../utils" export const itemsMergeResolver: MergeResolver = (args, ctx) => { diff --git a/src/resolvers/properties.ts b/src/resolvers/properties.ts index 842d217..b515c98 100644 --- a/src/resolvers/properties.ts +++ b/src/resolvers/properties.ts @@ -1,5 +1,5 @@ import { getAllOfItemsMap, jsonSchemaMergeResolver } from "./jsonschema" -import { JsonSchema, MergeResolver } from "../types" +import type { JsonSchema, MergeResolver } from "../types" import { MapArray } from "../utils" export const getPropertiesForMerge = (allOfItems: JsonSchema[]) => { diff --git a/src/rules/graphapi.ts b/src/rules/graphapi.ts index ddcb783..c8dccbc 100644 --- a/src/rules/graphapi.ts +++ b/src/rules/graphapi.ts @@ -1,6 +1,6 @@ import { jsonSchemaMergeRules } from "./jsonschema" +import type { MergeRules } from "../types" import * as resolvers from "../resolvers" -import { MergeRules } from "../types" const graphSchemaMergeRules: MergeRules = jsonSchemaMergeRules("draft-06", { "/args": () => graphSchemaMergeRules, diff --git a/src/rules/jsonschema.ts b/src/rules/jsonschema.ts index 865532b..a418a06 100644 --- a/src/rules/jsonschema.ts +++ b/src/rules/jsonschema.ts @@ -1,5 +1,5 @@ +import type { MergeRules } from "../types" import * as resolvers from "../resolvers" -import { MergeRules } from "../types" export const jsonSchemaVersion = ["draft-04", "draft-06"] as const diff --git a/src/rules/openapi.ts b/src/rules/openapi.ts index 9964881..b2b896f 100644 --- a/src/rules/openapi.ts +++ b/src/rules/openapi.ts @@ -1,6 +1,6 @@ import { JsonSchemaVersion, jsonSchemaMergeRules } from "./jsonschema" +import type { MergeRules } from "../types" import * as resolvers from "../resolvers" -import { MergeRules } from "../types" export const openApiVersion = ["3.0.x", "3.1.x"] as const diff --git a/src/types.ts b/src/types.ts index 2b8a4ae..f90f3a7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { JsonPath, CrawlRules } from "json-crawl" +import type { JsonPath, CrawlRules } from "json-crawl" export type JsonSchema = any export type MergeRules = CrawlRules diff --git a/src/utils.ts b/src/utils.ts index 5b6d492..9a3b3d2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,6 @@ -import { JsonPath, isObject } from "json-crawl" +import { type JsonPath, isObject } from "json-crawl" -import { AnyOfNode, OneOfNode, RefNode } from "./types" +import type { AnyOfNode, OneOfNode, RefNode } from "./types" export class MapArray extends Map> { public add(key: K, value: V): this { diff --git a/test/merge.cycleRefs.test.ts b/test/merge.cycleRefs.test.ts index e445464..4163864 100644 --- a/test/merge.cycleRefs.test.ts +++ b/test/merge.cycleRefs.test.ts @@ -1,6 +1,6 @@ import { merge } from "../src" -describe("cycle refs", () => { +describe("cycle $refs", () => { it("should support cycle refs in allOf", () => { const data = { type: 'object', @@ -28,35 +28,112 @@ describe("cycle refs", () => { }, } - const result = merge(data) + const result: any = merge(data) - expect(result).toEqual( { + expect(result).toMatchObject( { type: 'object', properties: { foo: { description: '1-st parent', type: 'object', properties: { - foo: { - $ref: '#/properties/foo', + foo: result.properties.foo, + baz: result.properties.baz, + } + }, + baz: { + description: '2-st parent', + type: 'object', + properties: { + foo: result.properties.foo, + baz: result.properties.baz, + } + }, + }, + }) + + // expect(result).toEqual( { + // type: 'object', + // properties: { + // foo: { + // description: '1-st parent', + // type: 'object', + // properties: { + // foo: { + // $ref: '#/properties/foo', + // }, + // baz: { + // description: '2-st parent', + // type: 'object', + // properties: { + // foo: { + // $ref: '#/properties/foo', + // }, + // baz: { + // $ref: '#/properties/foo/properties/baz', + // }, + // } + // }, + + // } + // }, + // baz: { + // $ref: '#/properties/foo/properties/baz', + // }, + // }, + // }) + }) + + it("should support dereferenced cycle refs in allOf", () => { + const data: any = { + type: 'object', + properties: { + foo: { + allOf: [ + { + description: '1-st parent', + }, + { + $ref: '#', }, - baz: { + ], + }, + baz: { + allOf: [ + { description: '2-st parent', - type: 'object', - properties: { - foo: { - $ref: '#/properties/foo', - }, - baz: { - $ref: '#/properties/foo/properties/baz', - }, - } }, + { + $ref: '#', + }, + ], + }, + }, + } + + data.properties.foo.allOf[1] = data + data.properties.baz.allOf[1] = data + const result: any = merge(data) + + expect(result).toMatchObject({ + type: 'object', + properties: { + foo: { + description: '1-st parent', + type: 'object', + properties: { + foo: result.properties.foo, + baz: result.properties.baz, } }, baz: { - $ref: '#/properties/foo/properties/baz', + description: '2-st parent', + type: 'object', + properties: { + foo: result.properties.foo, + baz: result.properties.baz, + } }, }, }) diff --git a/yarn.lock b/yarn.lock index a9b8e25..586d330 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2482,10 +2482,10 @@ jsesc@^2.5.1: resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -json-crawl@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/json-crawl/-/json-crawl-0.4.2.tgz#34339e4984bdf3a7f39518f1e3a0cd29ac1cc86c" - integrity sha512-MOKk9cjtpMrP4H1DmG+PtS7aFWg9OuSqxc/wpFcOE++yVnD5Bi5iKoXD6oqs+kltRwJRgZBYMozRNpQpxD/TJw== +json-crawl@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json-crawl/-/json-crawl-0.5.1.tgz#1dcd753ee1bcbebe15934f350bb577e422e5c16b" + integrity sha512-guQYl5NFDUC6XtJvlMb80rYTJ0LhY9lLlDpL6idDwSGldpGayWBzsstK7BlmULXM/WsT0jI+skiilwiRb904wA== json-parse-even-better-errors@^2.3.0: version "2.3.1"