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
|
||||
AdminShippingOption:
|
||||
- AdminShippingOption
|
||||
- AdminServiceZone
|
||||
AdminProductCategory:
|
||||
- AdminProductCategory
|
||||
- AdminProduct
|
||||
@@ -41,6 +42,8 @@ decorators:
|
||||
AdminTaxRegion:
|
||||
- AdminTaxRegion
|
||||
- AdminTaxRate
|
||||
AdminInventoryLevel:
|
||||
- AdminInventoryItem
|
||||
theme:
|
||||
openapi:
|
||||
theme:
|
||||
|
||||
@@ -238,10 +238,13 @@ ${hint}
|
||||
`
|
||||
const redoclyConfigPath = path.join(basePath, "redocly", "redocly-config.yaml")
|
||||
const originalContent = await readYaml(redoclyConfigPath) as CircularReferenceConfig
|
||||
originalContent.decorators["medusa/circular-patch"].schemas = Object.assign(
|
||||
originalContent.decorators["medusa/circular-patch"].schemas,
|
||||
recommendation
|
||||
)
|
||||
Object.keys(recommendation).forEach((recKey) => {
|
||||
originalContent.decorators["medusa/circular-patch"].schemas[recKey] = [
|
||||
...originalContent.decorators["medusa/circular-patch"].schemas[recKey],
|
||||
...recommendation[recKey]
|
||||
]
|
||||
})
|
||||
|
||||
await writeYaml(redoclyConfigPath, jsonObjectToYamlString(originalContent))
|
||||
console.log(`🟡 Added the following unhandled circular references to redocly-config.ts:` + hintMessage)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client"
|
||||
|
||||
import type { SchemaObject } from "@/types/openapi"
|
||||
import TagOperationParametersDefault from "../Default"
|
||||
import dynamic from "next/dynamic"
|
||||
@@ -5,6 +7,7 @@ import type { TagOperationParametersProps } from "../.."
|
||||
import type { TagsOperationParametersNestedProps } from "../../Nested"
|
||||
import checkRequired from "@/utils/check-required"
|
||||
import { Loading, type DetailsProps } from "docs-ui"
|
||||
import { useMemo } from "react"
|
||||
|
||||
const TagOperationParameters = dynamic<TagOperationParametersProps>(
|
||||
async () => import("../.."),
|
||||
@@ -41,9 +44,22 @@ const TagOperationParametersObject = ({
|
||||
isRequired,
|
||||
topLevel = false,
|
||||
}: 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 (
|
||||
(schema.type !== "object" && schema.type !== undefined) ||
|
||||
(!schema.properties && !name)
|
||||
(isPropertiesEmpty && isAdditionalPropertiesEmpty && !name)
|
||||
) {
|
||||
return <></>
|
||||
}
|
||||
@@ -65,22 +81,19 @@ const TagOperationParametersObject = ({
|
||||
}
|
||||
|
||||
const getPropertyParameterElms = (isNested = false) => {
|
||||
const properties = isPropertiesEmpty
|
||||
? schema.additionalProperties!.properties
|
||||
: schema.properties
|
||||
// sort properties to show required fields first
|
||||
const sortedProperties = Object.keys(schema.properties).sort(
|
||||
const sortedProperties = Object.keys(properties).sort(
|
||||
(property1, property2) => {
|
||||
schema.properties[property1].isRequired = checkRequired(
|
||||
schema,
|
||||
property1
|
||||
)
|
||||
schema.properties[property2].isRequired = checkRequired(
|
||||
schema,
|
||||
property2
|
||||
)
|
||||
properties[property1].isRequired = checkRequired(schema, property1)
|
||||
properties[property2].isRequired = checkRequired(schema, property2)
|
||||
|
||||
return schema.properties[property1].isRequired &&
|
||||
schema.properties[property2].isRequired
|
||||
return properties[property1].isRequired &&
|
||||
properties[property2].isRequired
|
||||
? 0
|
||||
: schema.properties[property1].isRequired
|
||||
: properties[property1].isRequired
|
||||
? -1
|
||||
: 1
|
||||
}
|
||||
@@ -90,13 +103,12 @@ const TagOperationParametersObject = ({
|
||||
{sortedProperties.map((property, index) => (
|
||||
<TagOperationParameters
|
||||
schemaObject={{
|
||||
...schema.properties[property],
|
||||
...properties[property],
|
||||
parameterName: property,
|
||||
}}
|
||||
key={index}
|
||||
isRequired={
|
||||
schema.properties[property].isRequired ||
|
||||
checkRequired(schema, property)
|
||||
properties[property].isRequired || checkRequired(schema, property)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
@@ -114,7 +126,7 @@ const TagOperationParametersObject = ({
|
||||
)
|
||||
}
|
||||
|
||||
if (!schema.properties || !Object.values(schema.properties).length) {
|
||||
if (isPropertiesEmpty && isAdditionalPropertiesEmpty) {
|
||||
return getPropertyDescriptionElm()
|
||||
}
|
||||
|
||||
|
||||
@@ -72,9 +72,15 @@ export type ArraySchemaObject = Omit<
|
||||
|
||||
export type NonArraySchemaObject = Omit<
|
||||
OpenAPIV3.NonArraySchemaObject,
|
||||
"properties" | "anyOf" | "allOf" | "oneOf" | "examples"
|
||||
| "properties"
|
||||
| "anyOf"
|
||||
| "allOf"
|
||||
| "oneOf"
|
||||
| "examples"
|
||||
| "additionalProperties"
|
||||
> & {
|
||||
properties: PropertiesObject
|
||||
additionalProperties?: SchemaObject
|
||||
anyOf?: SchemaObject[]
|
||||
allOf?: SchemaObject[]
|
||||
oneOf?: SchemaObject[]
|
||||
@@ -90,6 +96,7 @@ export type SchemaObject = (ArraySchemaObject | NonArraySchemaObject) & {
|
||||
"x-featureFlag"?: string
|
||||
"x-expandable"?: string
|
||||
"x-schemaName"?: string
|
||||
additionalProperties?: SchemaObject
|
||||
}
|
||||
|
||||
export type PropertiesObject = {
|
||||
|
||||
@@ -1,14 +1,48 @@
|
||||
/**
|
||||
* @schema AdminWorkflowExecutionExecution
|
||||
* type: object
|
||||
* description: The workflow execution's execution.
|
||||
* description: The workflow execution's steps details.
|
||||
* x-schemaName: AdminWorkflowExecutionExecution
|
||||
* required:
|
||||
* - steps
|
||||
* properties:
|
||||
* steps:
|
||||
* 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
|
||||
// and convert those
|
||||
if (schema.properties) {
|
||||
Object.keys(schema.properties).forEach((property) => {
|
||||
const propertySchema = schema.properties![property]
|
||||
const properties = schema.properties
|
||||
? schema.properties
|
||||
: 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) {
|
||||
return
|
||||
}
|
||||
@@ -105,7 +112,7 @@ class OasSchemaHelper {
|
||||
})
|
||||
}
|
||||
|
||||
schema.properties![property] =
|
||||
properties![property] =
|
||||
this.namedSchemaToReference(
|
||||
propertySchema as OpenApiSchema,
|
||||
level + 1
|
||||
@@ -178,6 +185,28 @@ class OasSchemaHelper {
|
||||
this.namedSchemaToReference(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
|
||||
@@ -186,10 +215,17 @@ class OasSchemaHelper {
|
||||
isSchemaEmpty(schema: OpenApiSchema): boolean {
|
||||
switch (schema.type) {
|
||||
case "object":
|
||||
return (
|
||||
const isPropertiesEmpty =
|
||||
schema.properties === undefined ||
|
||||
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":
|
||||
return (
|
||||
!this.isRefObject(schema.items) && this.isSchemaEmpty(schema.items)
|
||||
@@ -350,6 +386,7 @@ class OasSchemaHelper {
|
||||
| OpenApiSchema
|
||||
| OpenAPIV3.RequestBodyObject
|
||||
| OpenAPIV3.ResponseObject
|
||||
| OpenAPIV3.ParameterObject
|
||||
| undefined
|
||||
): schema is OpenAPIV3.ReferenceObject {
|
||||
return schema !== undefined && "$ref" in schema
|
||||
|
||||
@@ -1512,10 +1512,6 @@ class OasKindGenerator extends FunctionKindGenerator {
|
||||
case itemType.isClassOrInterface() ||
|
||||
itemType.isTypeParameter() ||
|
||||
(itemType as ts.Type).flags === ts.TypeFlags.Object:
|
||||
const properties: Record<
|
||||
string,
|
||||
OpenApiSchema | OpenAPIV3.ReferenceObject
|
||||
> = {}
|
||||
const requiredProperties: string[] = []
|
||||
|
||||
const baseType = itemType.getBaseTypes()?.[0]
|
||||
@@ -1535,8 +1531,26 @@ class OasKindGenerator extends FunctionKindGenerator {
|
||||
required: undefined,
|
||||
}
|
||||
|
||||
const properties: Record<
|
||||
string,
|
||||
OpenApiSchema | OpenAPIV3.ReferenceObject
|
||||
> = {}
|
||||
let isAdditionalProperties = false
|
||||
|
||||
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 (
|
||||
(allowedChildren && !allowedChildren.includes(property.name)) ||
|
||||
(disallowedChildren && disallowedChildren.includes(property.name))
|
||||
@@ -1624,7 +1638,14 @@ class OasKindGenerator extends FunctionKindGenerator {
|
||||
}
|
||||
|
||||
if (Object.values(properties).length) {
|
||||
objSchema.properties = properties
|
||||
if (isAdditionalProperties) {
|
||||
objSchema.additionalProperties = {
|
||||
type: "object",
|
||||
properties,
|
||||
}
|
||||
} else {
|
||||
objSchema.properties = properties
|
||||
}
|
||||
}
|
||||
|
||||
objSchema.required =
|
||||
@@ -1987,6 +2008,26 @@ class OasKindGenerator extends FunctionKindGenerator {
|
||||
oldSchemaObj!.properties = newSchemaObj.properties
|
||||
} else if (!newSchemaObj?.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 {
|
||||
// update existing properties
|
||||
Object.entries(oldSchemaObj!.properties!).forEach(
|
||||
|
||||
@@ -175,6 +175,30 @@ export default async function () {
|
||||
})
|
||||
|
||||
// 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 (oasSchemaHelper.isRefObject(oas.requestBody)) {
|
||||
referencedSchemas.add(
|
||||
|
||||
Reference in New Issue
Block a user