fix(oas): support additional props, fix circular references patch, and other fixes (#9213)
* chore(oas): support additional props, fix circular references patch, and other fixes * fix description * description fixes
This commit is contained in:
@@ -16,6 +16,7 @@ decorators:
|
|||||||
- ProductCategoryResponse
|
- ProductCategoryResponse
|
||||||
AdminShippingOption:
|
AdminShippingOption:
|
||||||
- AdminShippingOption
|
- AdminShippingOption
|
||||||
|
- AdminServiceZone
|
||||||
AdminProductCategory:
|
AdminProductCategory:
|
||||||
- AdminProductCategory
|
- AdminProductCategory
|
||||||
- AdminProduct
|
- AdminProduct
|
||||||
@@ -41,6 +42,8 @@ decorators:
|
|||||||
AdminTaxRegion:
|
AdminTaxRegion:
|
||||||
- AdminTaxRegion
|
- AdminTaxRegion
|
||||||
- AdminTaxRate
|
- AdminTaxRate
|
||||||
|
AdminInventoryLevel:
|
||||||
|
- AdminInventoryItem
|
||||||
theme:
|
theme:
|
||||||
openapi:
|
openapi:
|
||||||
theme:
|
theme:
|
||||||
|
|||||||
@@ -238,10 +238,13 @@ ${hint}
|
|||||||
`
|
`
|
||||||
const redoclyConfigPath = path.join(basePath, "redocly", "redocly-config.yaml")
|
const redoclyConfigPath = path.join(basePath, "redocly", "redocly-config.yaml")
|
||||||
const originalContent = await readYaml(redoclyConfigPath) as CircularReferenceConfig
|
const originalContent = await readYaml(redoclyConfigPath) as CircularReferenceConfig
|
||||||
originalContent.decorators["medusa/circular-patch"].schemas = Object.assign(
|
Object.keys(recommendation).forEach((recKey) => {
|
||||||
originalContent.decorators["medusa/circular-patch"].schemas,
|
originalContent.decorators["medusa/circular-patch"].schemas[recKey] = [
|
||||||
recommendation
|
...originalContent.decorators["medusa/circular-patch"].schemas[recKey],
|
||||||
)
|
...recommendation[recKey]
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
await writeYaml(redoclyConfigPath, jsonObjectToYamlString(originalContent))
|
await writeYaml(redoclyConfigPath, jsonObjectToYamlString(originalContent))
|
||||||
console.log(`🟡 Added the following unhandled circular references to redocly-config.ts:` + hintMessage)
|
console.log(`🟡 Added the following unhandled circular references to redocly-config.ts:` + hintMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-17
@@ -1,3 +1,5 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
import type { SchemaObject } from "@/types/openapi"
|
import type { SchemaObject } from "@/types/openapi"
|
||||||
import TagOperationParametersDefault from "../Default"
|
import TagOperationParametersDefault from "../Default"
|
||||||
import dynamic from "next/dynamic"
|
import dynamic from "next/dynamic"
|
||||||
@@ -5,6 +7,7 @@ import type { TagOperationParametersProps } from "../.."
|
|||||||
import type { TagsOperationParametersNestedProps } from "../../Nested"
|
import type { TagsOperationParametersNestedProps } from "../../Nested"
|
||||||
import checkRequired from "@/utils/check-required"
|
import checkRequired from "@/utils/check-required"
|
||||||
import { Loading, type DetailsProps } from "docs-ui"
|
import { Loading, type DetailsProps } from "docs-ui"
|
||||||
|
import { useMemo } from "react"
|
||||||
|
|
||||||
const TagOperationParameters = dynamic<TagOperationParametersProps>(
|
const TagOperationParameters = dynamic<TagOperationParametersProps>(
|
||||||
async () => import("../.."),
|
async () => import("../.."),
|
||||||
@@ -41,9 +44,22 @@ const TagOperationParametersObject = ({
|
|||||||
isRequired,
|
isRequired,
|
||||||
topLevel = false,
|
topLevel = false,
|
||||||
}: TagOperationParametersObjectProps) => {
|
}: TagOperationParametersObjectProps) => {
|
||||||
|
const isPropertiesEmpty = useMemo(
|
||||||
|
() => !schema.properties || !Object.values(schema.properties).length,
|
||||||
|
[schema]
|
||||||
|
)
|
||||||
|
const isAdditionalPropertiesEmpty = useMemo(
|
||||||
|
() =>
|
||||||
|
!schema.additionalProperties ||
|
||||||
|
schema.additionalProperties.type !== "object" ||
|
||||||
|
!schema.additionalProperties.properties ||
|
||||||
|
!Object.values(schema.additionalProperties.properties).length,
|
||||||
|
[schema]
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(schema.type !== "object" && schema.type !== undefined) ||
|
(schema.type !== "object" && schema.type !== undefined) ||
|
||||||
(!schema.properties && !name)
|
(isPropertiesEmpty && isAdditionalPropertiesEmpty && !name)
|
||||||
) {
|
) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
@@ -65,22 +81,19 @@ const TagOperationParametersObject = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getPropertyParameterElms = (isNested = false) => {
|
const getPropertyParameterElms = (isNested = false) => {
|
||||||
|
const properties = isPropertiesEmpty
|
||||||
|
? schema.additionalProperties!.properties
|
||||||
|
: schema.properties
|
||||||
// sort properties to show required fields first
|
// sort properties to show required fields first
|
||||||
const sortedProperties = Object.keys(schema.properties).sort(
|
const sortedProperties = Object.keys(properties).sort(
|
||||||
(property1, property2) => {
|
(property1, property2) => {
|
||||||
schema.properties[property1].isRequired = checkRequired(
|
properties[property1].isRequired = checkRequired(schema, property1)
|
||||||
schema,
|
properties[property2].isRequired = checkRequired(schema, property2)
|
||||||
property1
|
|
||||||
)
|
|
||||||
schema.properties[property2].isRequired = checkRequired(
|
|
||||||
schema,
|
|
||||||
property2
|
|
||||||
)
|
|
||||||
|
|
||||||
return schema.properties[property1].isRequired &&
|
return properties[property1].isRequired &&
|
||||||
schema.properties[property2].isRequired
|
properties[property2].isRequired
|
||||||
? 0
|
? 0
|
||||||
: schema.properties[property1].isRequired
|
: properties[property1].isRequired
|
||||||
? -1
|
? -1
|
||||||
: 1
|
: 1
|
||||||
}
|
}
|
||||||
@@ -90,13 +103,12 @@ const TagOperationParametersObject = ({
|
|||||||
{sortedProperties.map((property, index) => (
|
{sortedProperties.map((property, index) => (
|
||||||
<TagOperationParameters
|
<TagOperationParameters
|
||||||
schemaObject={{
|
schemaObject={{
|
||||||
...schema.properties[property],
|
...properties[property],
|
||||||
parameterName: property,
|
parameterName: property,
|
||||||
}}
|
}}
|
||||||
key={index}
|
key={index}
|
||||||
isRequired={
|
isRequired={
|
||||||
schema.properties[property].isRequired ||
|
properties[property].isRequired || checkRequired(schema, property)
|
||||||
checkRequired(schema, property)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -114,7 +126,7 @@ const TagOperationParametersObject = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!schema.properties || !Object.values(schema.properties).length) {
|
if (isPropertiesEmpty && isAdditionalPropertiesEmpty) {
|
||||||
return getPropertyDescriptionElm()
|
return getPropertyDescriptionElm()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,9 +72,15 @@ export type ArraySchemaObject = Omit<
|
|||||||
|
|
||||||
export type NonArraySchemaObject = Omit<
|
export type NonArraySchemaObject = Omit<
|
||||||
OpenAPIV3.NonArraySchemaObject,
|
OpenAPIV3.NonArraySchemaObject,
|
||||||
"properties" | "anyOf" | "allOf" | "oneOf" | "examples"
|
| "properties"
|
||||||
|
| "anyOf"
|
||||||
|
| "allOf"
|
||||||
|
| "oneOf"
|
||||||
|
| "examples"
|
||||||
|
| "additionalProperties"
|
||||||
> & {
|
> & {
|
||||||
properties: PropertiesObject
|
properties: PropertiesObject
|
||||||
|
additionalProperties?: SchemaObject
|
||||||
anyOf?: SchemaObject[]
|
anyOf?: SchemaObject[]
|
||||||
allOf?: SchemaObject[]
|
allOf?: SchemaObject[]
|
||||||
oneOf?: SchemaObject[]
|
oneOf?: SchemaObject[]
|
||||||
@@ -90,6 +96,7 @@ export type SchemaObject = (ArraySchemaObject | NonArraySchemaObject) & {
|
|||||||
"x-featureFlag"?: string
|
"x-featureFlag"?: string
|
||||||
"x-expandable"?: string
|
"x-expandable"?: string
|
||||||
"x-schemaName"?: string
|
"x-schemaName"?: string
|
||||||
|
additionalProperties?: SchemaObject
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PropertiesObject = {
|
export type PropertiesObject = {
|
||||||
|
|||||||
@@ -1,14 +1,48 @@
|
|||||||
/**
|
/**
|
||||||
* @schema AdminWorkflowExecutionExecution
|
* @schema AdminWorkflowExecutionExecution
|
||||||
* type: object
|
* type: object
|
||||||
* description: The workflow execution's execution.
|
* description: The workflow execution's steps details.
|
||||||
* x-schemaName: AdminWorkflowExecutionExecution
|
* x-schemaName: AdminWorkflowExecutionExecution
|
||||||
* required:
|
* required:
|
||||||
* - steps
|
* - steps
|
||||||
* properties:
|
* properties:
|
||||||
* steps:
|
* steps:
|
||||||
* type: object
|
* type: object
|
||||||
* description: The execution's steps.
|
* description: The execution's steps. Each object key is a step ID, and the value is the object whose properties are shown below.
|
||||||
|
* required:
|
||||||
|
* - id
|
||||||
|
* - invoke
|
||||||
|
* - definition
|
||||||
|
* - compensate
|
||||||
|
* - depth
|
||||||
|
* - startedAt
|
||||||
|
* additionalProperties:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: string
|
||||||
|
* title: id
|
||||||
|
* description: The step's ID.
|
||||||
|
* invoke:
|
||||||
|
* type: object
|
||||||
|
* description: The state of the step's invokation function.
|
||||||
|
* x-schemaName: WorkflowExecutionFn
|
||||||
|
* definition:
|
||||||
|
* type: object
|
||||||
|
* description: The step's definition details.
|
||||||
|
* x-schemaName: WorkflowExecutionDefinition
|
||||||
|
* compensate:
|
||||||
|
* type: object
|
||||||
|
* description: The state of the step's compensation function.
|
||||||
|
* x-schemaName: WorkflowExecutionFn
|
||||||
|
* depth:
|
||||||
|
* type: number
|
||||||
|
* title: depth
|
||||||
|
* description: The step's depth in the workflow's execution.
|
||||||
|
* startedAt:
|
||||||
|
* type: number
|
||||||
|
* title: startedAt
|
||||||
|
* description: The timestamp the step started executing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -69,9 +69,16 @@ class OasSchemaHelper {
|
|||||||
|
|
||||||
// check if schema has child schemas
|
// check if schema has child schemas
|
||||||
// and convert those
|
// and convert those
|
||||||
if (schema.properties) {
|
const properties = schema.properties
|
||||||
Object.keys(schema.properties).forEach((property) => {
|
? schema.properties
|
||||||
const propertySchema = schema.properties![property]
|
: schema.additionalProperties &&
|
||||||
|
typeof schema.additionalProperties !== "boolean" &&
|
||||||
|
!this.isRefObject(schema.additionalProperties)
|
||||||
|
? schema.additionalProperties.properties
|
||||||
|
: undefined
|
||||||
|
if (properties) {
|
||||||
|
Object.keys(properties).forEach((property) => {
|
||||||
|
const propertySchema = properties![property]
|
||||||
if ("$ref" in propertySchema) {
|
if ("$ref" in propertySchema) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -105,7 +112,7 @@ class OasSchemaHelper {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.properties![property] =
|
properties![property] =
|
||||||
this.namedSchemaToReference(
|
this.namedSchemaToReference(
|
||||||
propertySchema as OpenApiSchema,
|
propertySchema as OpenApiSchema,
|
||||||
level + 1
|
level + 1
|
||||||
@@ -178,6 +185,28 @@ class OasSchemaHelper {
|
|||||||
this.namedSchemaToReference(transformedProperty) ||
|
this.namedSchemaToReference(transformedProperty) ||
|
||||||
transformedProperty
|
transformedProperty
|
||||||
})
|
})
|
||||||
|
} else if (
|
||||||
|
clonedSchema.additionalProperties &&
|
||||||
|
typeof clonedSchema.additionalProperties !== "boolean" &&
|
||||||
|
!this.isRefObject(clonedSchema.additionalProperties) &&
|
||||||
|
clonedSchema.additionalProperties.properties
|
||||||
|
) {
|
||||||
|
const additionalProps = schema.additionalProperties as OpenApiSchema
|
||||||
|
Object.entries(clonedSchema.additionalProperties.properties).forEach(
|
||||||
|
([key, property]) => {
|
||||||
|
if (this.isRefObject(property)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const transformedProperty = this.schemaChildrenToRefs(
|
||||||
|
property,
|
||||||
|
level + 1
|
||||||
|
)
|
||||||
|
additionalProps.properties![key] =
|
||||||
|
this.namedSchemaToReference(transformedProperty) ||
|
||||||
|
transformedProperty
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return clonedSchema
|
return clonedSchema
|
||||||
@@ -186,10 +215,17 @@ class OasSchemaHelper {
|
|||||||
isSchemaEmpty(schema: OpenApiSchema): boolean {
|
isSchemaEmpty(schema: OpenApiSchema): boolean {
|
||||||
switch (schema.type) {
|
switch (schema.type) {
|
||||||
case "object":
|
case "object":
|
||||||
return (
|
const isPropertiesEmpty =
|
||||||
schema.properties === undefined ||
|
schema.properties === undefined ||
|
||||||
Object.keys(schema.properties).length === 0
|
Object.keys(schema.properties).length === 0
|
||||||
)
|
const isAdditionalPropertiesEmpty =
|
||||||
|
schema.additionalProperties === undefined ||
|
||||||
|
typeof schema.additionalProperties === "boolean" ||
|
||||||
|
(!this.isRefObject(schema.additionalProperties) &&
|
||||||
|
(schema.additionalProperties.properties === undefined ||
|
||||||
|
Object.keys(schema.additionalProperties.properties).length == 0))
|
||||||
|
|
||||||
|
return isPropertiesEmpty && isAdditionalPropertiesEmpty
|
||||||
case "array":
|
case "array":
|
||||||
return (
|
return (
|
||||||
!this.isRefObject(schema.items) && this.isSchemaEmpty(schema.items)
|
!this.isRefObject(schema.items) && this.isSchemaEmpty(schema.items)
|
||||||
@@ -350,6 +386,7 @@ class OasSchemaHelper {
|
|||||||
| OpenApiSchema
|
| OpenApiSchema
|
||||||
| OpenAPIV3.RequestBodyObject
|
| OpenAPIV3.RequestBodyObject
|
||||||
| OpenAPIV3.ResponseObject
|
| OpenAPIV3.ResponseObject
|
||||||
|
| OpenAPIV3.ParameterObject
|
||||||
| undefined
|
| undefined
|
||||||
): schema is OpenAPIV3.ReferenceObject {
|
): schema is OpenAPIV3.ReferenceObject {
|
||||||
return schema !== undefined && "$ref" in schema
|
return schema !== undefined && "$ref" in schema
|
||||||
|
|||||||
@@ -1512,10 +1512,6 @@ class OasKindGenerator extends FunctionKindGenerator {
|
|||||||
case itemType.isClassOrInterface() ||
|
case itemType.isClassOrInterface() ||
|
||||||
itemType.isTypeParameter() ||
|
itemType.isTypeParameter() ||
|
||||||
(itemType as ts.Type).flags === ts.TypeFlags.Object:
|
(itemType as ts.Type).flags === ts.TypeFlags.Object:
|
||||||
const properties: Record<
|
|
||||||
string,
|
|
||||||
OpenApiSchema | OpenAPIV3.ReferenceObject
|
|
||||||
> = {}
|
|
||||||
const requiredProperties: string[] = []
|
const requiredProperties: string[] = []
|
||||||
|
|
||||||
const baseType = itemType.getBaseTypes()?.[0]
|
const baseType = itemType.getBaseTypes()?.[0]
|
||||||
@@ -1535,8 +1531,26 @@ class OasKindGenerator extends FunctionKindGenerator {
|
|||||||
required: undefined,
|
required: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const properties: Record<
|
||||||
|
string,
|
||||||
|
OpenApiSchema | OpenAPIV3.ReferenceObject
|
||||||
|
> = {}
|
||||||
|
let isAdditionalProperties = false
|
||||||
|
|
||||||
if (level + 1 <= this.MAX_LEVEL) {
|
if (level + 1 <= this.MAX_LEVEL) {
|
||||||
itemType.getProperties().forEach((property) => {
|
let itemProperties = itemType.getProperties()
|
||||||
|
|
||||||
|
if (
|
||||||
|
!itemProperties.length &&
|
||||||
|
itemType.aliasTypeArguments?.length === 2 &&
|
||||||
|
itemType.aliasTypeArguments[0].flags === ts.TypeFlags.String
|
||||||
|
) {
|
||||||
|
// object has dynamic keys, so put the properties under additionalProperties
|
||||||
|
itemProperties = itemType.aliasTypeArguments[1].getProperties()
|
||||||
|
isAdditionalProperties = true
|
||||||
|
}
|
||||||
|
|
||||||
|
itemProperties.forEach((property) => {
|
||||||
if (
|
if (
|
||||||
(allowedChildren && !allowedChildren.includes(property.name)) ||
|
(allowedChildren && !allowedChildren.includes(property.name)) ||
|
||||||
(disallowedChildren && disallowedChildren.includes(property.name))
|
(disallowedChildren && disallowedChildren.includes(property.name))
|
||||||
@@ -1624,7 +1638,14 @@ class OasKindGenerator extends FunctionKindGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Object.values(properties).length) {
|
if (Object.values(properties).length) {
|
||||||
objSchema.properties = properties
|
if (isAdditionalProperties) {
|
||||||
|
objSchema.additionalProperties = {
|
||||||
|
type: "object",
|
||||||
|
properties,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
objSchema.properties = properties
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objSchema.required =
|
objSchema.required =
|
||||||
@@ -1987,6 +2008,26 @@ class OasKindGenerator extends FunctionKindGenerator {
|
|||||||
oldSchemaObj!.properties = newSchemaObj.properties
|
oldSchemaObj!.properties = newSchemaObj.properties
|
||||||
} else if (!newSchemaObj?.properties) {
|
} else if (!newSchemaObj?.properties) {
|
||||||
delete oldSchemaObj!.properties
|
delete oldSchemaObj!.properties
|
||||||
|
|
||||||
|
// check if additionalProperties should be updated
|
||||||
|
if (
|
||||||
|
!oldSchemaObj!.additionalProperties &&
|
||||||
|
newSchemaObj.additionalProperties
|
||||||
|
) {
|
||||||
|
oldSchemaObj!.additionalProperties = newSchemaObj.additionalProperties
|
||||||
|
} else if (!newSchemaObj.additionalProperties) {
|
||||||
|
delete oldSchemaObj!.additionalProperties
|
||||||
|
} else if (
|
||||||
|
typeof oldSchemaObj!.additionalProperties !== "boolean" &&
|
||||||
|
typeof newSchemaObj!.additionalProperties !== "boolean"
|
||||||
|
) {
|
||||||
|
oldSchemaObj!.additionalProperties =
|
||||||
|
this.updateSchema({
|
||||||
|
oldSchema: oldSchemaObj!.additionalProperties,
|
||||||
|
newSchema: newSchemaObj.additionalProperties,
|
||||||
|
level: level + 1,
|
||||||
|
}) || oldSchemaObj!.additionalProperties
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// update existing properties
|
// update existing properties
|
||||||
Object.entries(oldSchemaObj!.properties!).forEach(
|
Object.entries(oldSchemaObj!.properties!).forEach(
|
||||||
|
|||||||
@@ -175,6 +175,30 @@ export default async function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// collect schemas
|
// collect schemas
|
||||||
|
oas.parameters?.forEach((parameter) => {
|
||||||
|
if (oasSchemaHelper.isRefObject(parameter)) {
|
||||||
|
referencedSchemas.add(
|
||||||
|
oasSchemaHelper.normalizeSchemaName(parameter.$ref)
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parameter.schema) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oasSchemaHelper.isRefObject(parameter.schema)) {
|
||||||
|
referencedSchemas.add(
|
||||||
|
oasSchemaHelper.normalizeSchemaName(parameter.schema.$ref)
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
testAndFindReferenceSchema(parameter.schema)
|
||||||
|
})
|
||||||
|
|
||||||
if (oas.requestBody) {
|
if (oas.requestBody) {
|
||||||
if (oasSchemaHelper.isRefObject(oas.requestBody)) {
|
if (oasSchemaHelper.isRefObject(oas.requestBody)) {
|
||||||
referencedSchemas.add(
|
referencedSchemas.add(
|
||||||
|
|||||||
Reference in New Issue
Block a user