From 4b7ab9968c149c8f3e66cb648cb3ed7dd513b387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Gorej?= Date: Wed, 31 May 2023 14:27:36 +0200 Subject: [PATCH] feat(oas31): enable overrides for samples plugin (#8731) These overrides are specific to OpenAPI 3.1.0 and JSON Schema 2020-12. Refs #8577 --- .../samples-extensions/fn.js | 25 +++++----- src/core/plugins/oas31/after-load.js | 38 +++++++++++++++ src/core/plugins/oas31/fn.js | 46 +++++++++---------- src/core/plugins/oas31/index.js | 42 ++++------------- .../json-schema-2020-12-extensions/fn.js | 4 +- .../plugins/oas31/wrap-components/models.jsx | 8 ++-- 6 files changed, 90 insertions(+), 73 deletions(-) create mode 100644 src/core/plugins/oas31/after-load.js diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn.js index 1902dccf17b..4a6f031958d 100644 --- a/src/core/plugins/json-schema-2020-12/samples-extensions/fn.js +++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn.js @@ -4,6 +4,7 @@ import XML from "xml" import RandExp from "randexp" import isEmpty from "lodash/isEmpty" + import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils" import memoizeN from "../../../../helpers/memoizeN" @@ -11,8 +12,8 @@ const generateStringFromRegex = (pattern) => { try { const randexp = new RandExp(pattern) return randexp.gen() - } catch (e) { - // Invalid regex should not cause a crash (regex syntax varies across languages) + } catch { + // invalid regex should not cause a crash (regex syntax varies across languages) return "string" } } @@ -36,17 +37,16 @@ const primitives = { const primitive = (schema) => { schema = objectify(schema) - let { type, format } = schema - - let fn = primitives[`${type}_${format}`] || primitives[type] - - if (isFunc(fn)) return fn(schema) + const { type, format } = schema + const fn = primitives[`${type}_${format}`] || primitives[type] - return "Unknown Type: " + schema.type + return typeof fn === "function" ? fn(schema) : `Unknown Type: ${schema.type}` } -// do a couple of quick sanity tests to ensure the value -// looks like a $$ref that swagger-client generates. +/** + * Do a couple of quick sanity tests to ensure the value + * looks like a $$ref that swagger-client generates. + */ const sanitizeRef = (value) => deeplyStripKey( value, @@ -720,8 +720,9 @@ export const createXMLExample = (schema, config, o) => { return XML(json, { declaration: true, indent: "\t" }) } -export const sampleFromSchema = (schema, config, o) => - sampleFromSchemaGeneric(schema, config, o, false) +export const sampleFromSchema = (schema, config, o) => { + return sampleFromSchemaGeneric(schema, config, o, false) +} const resolver = (arg1, arg2, arg3) => [ arg1, diff --git a/src/core/plugins/oas31/after-load.js b/src/core/plugins/oas31/after-load.js new file mode 100644 index 00000000000..51b4b619633 --- /dev/null +++ b/src/core/plugins/oas31/after-load.js @@ -0,0 +1,38 @@ +/** + * @prettier + */ +import { + makeIsExpandable, + getProperties, +} from "./json-schema-2020-12-extensions/fn" +import { wrapOAS31Fn } from "./fn" + +function afterLoad({ fn, getSystem }) { + // overrides for fn.jsonSchema202012 + if (fn.jsonSchema202012) { + const isExpandable = makeIsExpandable( + fn.jsonSchema202012.isExpandable, + getSystem + ) + + Object.assign(this.fn.jsonSchema202012, { isExpandable, getProperties }) + } + + // wraps schema generators from samples plugin and make them specific to OpenAPI 3.1 version + if (typeof fn.sampleFromSchema === "function" && fn.jsonSchema202012) { + const wrappedFns = wrapOAS31Fn( + { + sampleFromSchema: fn.jsonSchema202012.sampleFromSchema, + sampleFromSchemaGeneric: fn.jsonSchema202012.sampleFromSchemaGeneric, + createXMLExample: fn.jsonSchema202012.createXMLExample, + memoizedSampleFromSchema: fn.jsonSchema202012.memoizedSampleFromSchema, + memoizedCreateXMLExample: fn.jsonSchema202012.memoizedCreateXMLExample, + }, + getSystem() + ) + + Object.assign(this.fn, wrappedFns) + } +} + +export default afterLoad diff --git a/src/core/plugins/oas31/fn.js b/src/core/plugins/oas31/fn.js index dc7b0b29f4b..546f58b6db5 100644 --- a/src/core/plugins/oas31/fn.js +++ b/src/core/plugins/oas31/fn.js @@ -97,28 +97,28 @@ export const createOnlyOAS31ComponentWrapper = } /* eslint-enable react/jsx-filename-extension */ -/** Utilize JSON Schema 2020-12 samples **/ -const wrapSampleFn = - (fnName) => - (getSystem) => - (...args) => { - const { fn, specSelectors } = getSystem() - - if (specSelectors.isOpenAPI31()) { - return fn.jsonSchema202012[fnName](...args) - } +/** + * Runs the fn replacement implementation when spec is OpenAPI 3.1. + * Runs the fn original implementation otherwise. + * + * @param fn + * @param system + * @returns {{[p: string]: function(...[*]): *}} + */ +export const wrapOAS31Fn = (fn, system) => { + const { fn: systemFn, specSelectors } = system - return fn[fnName](...args) - } + return Object.fromEntries( + Object.entries(fn).map(([name, newImpl]) => { + const oriImpl = systemFn[name] + const impl = (...args) => + specSelectors.isOAS31() + ? newImpl(...args) + : typeof oriImpl === "function" + ? oriImpl(...args) + : undefined -export const wrapSampleFromSchema = wrapSampleFn("sampleFromSchema") -export const wrapSampleFromSchemaGeneric = wrapSampleFn( - "sampleFromSchemaGeneric" -) -export const wrapCreateXMLExample = wrapSampleFn("createXMLExample") -export const wrapMemoizedSampleFromSchema = wrapSampleFn( - "memoizedSampleFromSchema" -) -export const wrapMemoizedCreateXMLExample = wrapSampleFn( - "memoizedCreateXMLExample" -) + return [name, impl] + }) + ) +} diff --git a/src/core/plugins/oas31/index.js b/src/core/plugins/oas31/index.js index 6fb9db158f7..51ed5afdaeb 100644 --- a/src/core/plugins/oas31/index.js +++ b/src/core/plugins/oas31/index.js @@ -20,11 +20,6 @@ import { isOAS31 as isOAS31Fn, createOnlyOAS31Selector as createOnlyOAS31SelectorFn, createSystemSelector as createSystemSelectorFn, - wrapSampleFromSchema, - wrapSampleFromSchemaGeneric, - wrapCreateXMLExample, - wrapMemoizedSampleFromSchema, - wrapMemoizedCreateXMLExample, } from "./fn" import { license as selectLicense, @@ -64,40 +59,19 @@ import JSONSchema202012KeywordExternalDocs from "./json-schema-2020-12-extension import JSONSchema202012KeywordDescriptionWrapper from "./json-schema-2020-12-extensions/wrap-components/keywords/Description" import JSONSchema202012KeywordDefaultWrapper from "./json-schema-2020-12-extensions/wrap-components/keywords/Default" import JSONSchema202012KeywordPropertiesWrapper from "./json-schema-2020-12-extensions/wrap-components/keywords/Properties" -import { - makeIsExpandable, - getProperties, -} from "./json-schema-2020-12-extensions/fn" +import afterLoad from "./after-load" -const OAS31Plugin = ({ getSystem }) => { - const system = getSystem() - const { fn } = system +const OAS31Plugin = ({ fn }) => { const createSystemSelector = fn.createSystemSelector || createSystemSelectorFn const createOnlyOAS31Selector = fn.createOnlyOAS31Selector || createOnlyOAS31SelectorFn // prettier-ignore - const pluginFn = { - isOAs31: isOAS31Fn, - createSystemSelector: createSystemSelectorFn, - createOnlyOAS31Selector: createOnlyOAS31SelectorFn, - } - if (typeof fn.jsonSchema202012?.isExpandable === "function") { - pluginFn.jsonSchema202012 = { - ...fn.jsonSchema202012, - isExpandable: makeIsExpandable(fn.jsonSchema202012.isExpandable, system), - getProperties, - } - } - // wraps schema generators and make them specific to OpenAPI version - if (typeof system.fn.inferSchema === "function") { - pluginFn.sampleFromSchema = wrapSampleFromSchema(getSystem) - pluginFn.sampleFromSchemaGeneric = wrapSampleFromSchemaGeneric(getSystem) - pluginFn.createXMLExample = wrapCreateXMLExample(getSystem) - pluginFn.memoizedSampleFromSchema = wrapMemoizedSampleFromSchema(getSystem) - pluginFn.memoizedCreateXMLExample = wrapMemoizedCreateXMLExample(getSystem) - } - return { - fn: pluginFn, + afterLoad, + fn: { + isOAS31: isOAS31Fn, + createSystemSelector: createSystemSelectorFn, + createOnlyOAS31Selector: createOnlyOAS31SelectorFn, + }, components: { Webhooks, JsonSchemaDialect, diff --git a/src/core/plugins/oas31/json-schema-2020-12-extensions/fn.js b/src/core/plugins/oas31/json-schema-2020-12-extensions/fn.js index d13466de820..e9ce9c4cc12 100644 --- a/src/core/plugins/oas31/json-schema-2020-12-extensions/fn.js +++ b/src/core/plugins/oas31/json-schema-2020-12-extensions/fn.js @@ -1,7 +1,9 @@ /** * @prettier */ -export const makeIsExpandable = (original, { fn }) => { +export const makeIsExpandable = (original, getSystem) => { + const { fn } = getSystem() + if (typeof original !== "function") { return null } diff --git a/src/core/plugins/oas31/wrap-components/models.jsx b/src/core/plugins/oas31/wrap-components/models.jsx index 824c523c630..9902ec5e1a6 100644 --- a/src/core/plugins/oas31/wrap-components/models.jsx +++ b/src/core/plugins/oas31/wrap-components/models.jsx @@ -10,8 +10,7 @@ import { } from "../json-schema-2020-12-extensions/fn" const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => { - const system = getSystem() - const { getComponent, fn, getConfigs } = system + const { getComponent, fn, getConfigs } = getSystem() const configs = getConfigs() if (ModelsWrapper.ModelsWithJSONSchemaContext) { @@ -135,7 +134,10 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => { }, fn: { upperFirst: fn.upperFirst, - isExpandable: makeIsExpandable(fn.jsonSchema202012.isExpandable, system), + isExpandable: makeIsExpandable( + fn.jsonSchema202012.isExpandable, + getSystem + ), getProperties, }, })