From d01d8811486a75d86d5d6fbcbda42da54e7756e4 Mon Sep 17 00:00:00 2001 From: Damir Date: Tue, 26 Dec 2023 00:04:25 +0600 Subject: [PATCH] add auto select for merge rules based on input --- README.md | 12 ++++++------ package.json | 4 ++-- src/merge.ts | 20 +++++++++++++++++--- test/merge.graphapi.test.ts | 4 ++-- test/merge.openapi.test.ts | 6 +++--- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4d38c8c..278a3d5 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,16 @@ npm npm ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/udamir/allof-merge/ci.yml) npm type definitions ![Coveralls branch](https://img.shields.io/coverallsCoverage/github/udamir/allof-merge) GitHub -Merge schemas using allOf into a more readable composed schema free from allOf. +Merge schemas with allOf into a more readable composed schema free from allOf. ## Features -- Safe merging of schemas combined with allOf in whole JsonSchema based document -- Fastest implmentation - up to x4 times faster then other popular libraries +- Safe merging of schemas combined with allOf in whole document +- Fastest implmentation - up to x3 times faster then other popular libraries - Merged schema does not validate more or less than the original schema - Removes almost all logical impossibilities - Correctly merge additionalProperties, patternProperties and properties taking into account common validations - Correctly merge items and additionalItems taking into account common validations -- Supports rules extension to merge other document types and JsonSchema versions +- Supports custom rules to merge other document types and JsonSchema versions - Supports input with circular references (javaScript references) - Supports $refs and circular $refs either (internal references only) - Correctly merge of $refs with sibling content (optionally) @@ -108,7 +108,7 @@ interface MergeOptions { source?: any // custom merge rules - // (optional) default = jsonSchemaMergeRules("draft-06") + // (optional) default = auto select based on the input (jsonSchemaMergeRules, openapiMergeRules, graphapiMergeRules) rules?: MergeRules // merge $ref with sibling content @@ -135,7 +135,7 @@ You can find supported rules in the src/rules directory of this repository: ## Benchmark ``` -allof-merge x 800 ops/sec ±2.35% (90 runs sampled) +allof-merge x 657 ops/sec ±2.35% (90 runs sampled) json-schema-merge-allof x 217 ops/sec ±2.03% (86 runs sampled) Fastest is allof-merge ``` diff --git a/package.json b/package.json index 32fdb08..0fd2fd9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "allof-merge", - "version": "0.6.2", - "description": "Simplify your JsonSchema by combining allOf safely.", + "version": "0.6.3", + "description": "Simplify JsonSchema/Openapi by combining allOf safely", "module": "dist/index.mjs", "main": "dist/index.cjs", "browser": "dist/index.iife.js", diff --git a/src/merge.ts b/src/merge.ts index 63d59a3..5189371 100644 --- a/src/merge.ts +++ b/src/merge.ts @@ -1,15 +1,29 @@ -import { JsonPath, SyncCloneHook, isObject, syncClone } from "json-crawl" +import { type JsonPath, type SyncCloneHook, isObject, syncClone } from "json-crawl" import type { AllOfRef, MergeError, MergeOptions, MergeResolver, MergeRules } from "./types" +import { graphapiMergeRules, jsonSchemaMergeRules, openApiMergeRules } from "./rules" import { buildPointer, isAnyOfNode, isOneOfNode } from "./utils" import { mergeCombinarySibling } from "./resolvers/combinary" import { jsonSchemaMergeResolver } from "./resolvers" import { normalizeAllOfItems } from "./normalize" -import { jsonSchemaMergeRules } from "./rules" import { ErrorMessage } from "./errors" +export const selectMergeRules = (data: unknown): MergeRules => { + if (typeof data !== "object" || !data) { return jsonSchemaMergeRules() } + + if ("openapi" in data && typeof data.openapi === "string" && /3.+/.test(data.openapi)) { + const version = data.openapi.startsWith("3.1") ? "3.1.x" : "3.0.x" + return openApiMergeRules(version) + } + // if ("asyncapi" in data && typeof data.asyncapi === "string" && /2.+/.test(data?.asyncapi)) return asyncApi2MergeRules + // if ("swagger" in data && typeof data.swagger === "string" && /2.+/.test(data?.swagger)) return swagger2MergeRules + if ("graphapi" in data && typeof data.graphapi === "string") return graphapiMergeRules + return jsonSchemaMergeRules() +} + + export const merge = (value: any, options?: MergeOptions) => { - const rules: MergeRules = options?.rules || jsonSchemaMergeRules() + const rules: MergeRules = options?.rules ?? selectMergeRules(value) return syncClone(value, allOfResolverHook(options), { rules }) } diff --git a/test/merge.graphapi.test.ts b/test/merge.graphapi.test.ts index f230b3e..4074f86 100644 --- a/test/merge.graphapi.test.ts +++ b/test/merge.graphapi.test.ts @@ -1,5 +1,5 @@ -import { merge, graphapiMergeRules } from "../src" import { graphapi, yaml } from "./helpers" +import { merge } from "../src" describe("Build GraphApi", () => { @@ -55,7 +55,7 @@ describe("Build GraphApi", () => { } ` - const merged = merge(schema, { rules: graphapiMergeRules, mergeCombinarySibling: true, mergeRefSibling: true }) + const merged = merge(schema, { mergeCombinarySibling: true, mergeRefSibling: true }) const expected = yaml` graphapi: 0.1.2 diff --git a/test/merge.openapi.test.ts b/test/merge.openapi.test.ts index 05c4006..bca8381 100644 --- a/test/merge.openapi.test.ts +++ b/test/merge.openapi.test.ts @@ -1,10 +1,10 @@ -import { merge, openApiMergeRules } from "../src" +import { merge } from "../src" const source31x = require("./resources/openapi31x.json") const source30x = require("./resources/openapi30x.json") describe("merge allof in openapi schema", function () { it("merges schema in openapi 3.0.x", () => { - const result = merge(source30x, { rules: openApiMergeRules() }) + const result = merge(source30x) expect(result).toMatchObject({ openapi: "3.0.2", @@ -106,7 +106,7 @@ describe("merge allof in openapi schema", function () { }) it("merges schema in openapi 3.1.x", () => { - const result = merge(source31x, { rules: openApiMergeRules("3.1.x") }) + const result = merge(source31x) expect(result).toMatchObject({ openapi: "3.1.0",