Skip to content

Commit

Permalink
docs-util: support new query type argument (#10468)
Browse files Browse the repository at this point in the history
* add support for second query argument

* more fixes
  • Loading branch information
shahednasser authored Dec 6, 2024
1 parent e3459b1 commit abdd4c9
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ class SchemaFactory {
BigNumberValue: {
type: "number",
},
difference_due: {
type: "number",
},
refund_amount: {
type: "number",
},
File: {
type: "object",
description: "A File to upload.",
Expand Down
227 changes: 133 additions & 94 deletions www/utils/packages/docs-generator/src/classes/kinds/oas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class OasKindGenerator extends FunctionKindGenerator {
"MedusaRequest",
"RequestWithContext",
"AuthenticatedMedusaRequest",
"MedusaStoreRequest",
]
// as it's not always possible to detect authenticated request
// use this to override the default detection logic.
Expand Down Expand Up @@ -1015,120 +1016,158 @@ class OasKindGenerator extends FunctionKindGenerator {
*/
requestSchema?: OpenApiSchema
} {
const parameters: OpenAPIV3.ParameterObject[] = []
const queryParameters: OpenAPIV3.ParameterObject[] = []
let requestSchema: OpenApiSchema | undefined

if (
node.parameters[0].type &&
ts.isTypeReferenceNode(node.parameters[0].type)
!node.parameters[0].type ||
!ts.isTypeReferenceNode(node.parameters[0].type)
) {
const requestType = this.checker.getTypeFromTypeNode(
node.parameters[0].type
) as ts.TypeReference
// TODO for now I'll use the type for validatedQuery until
// we have an actual approach to infer query types
const querySymbol = requestType.getProperty("validatedQuery")
if (querySymbol) {
const { shouldAddFields, shouldAddPagination } =
this.shouldAddQueryParams(node)
const queryType = this.checker.getTypeOfSymbol(querySymbol)
const queryTypeName = this.checker.typeToString(queryType)
queryType.getProperties().forEach((property) => {
const propertyName = property.getName()
// if this is a field / pagination query parameter and
// they're not used in the route, don't add them.
if (
(this.FIELD_QUERY_PARAMS.includes(propertyName) &&
!shouldAddFields) ||
(this.PAGINATION_QUERY_PARAMS.includes(propertyName) &&
!shouldAddPagination)
) {
return
}
const propertyType = this.checker.getTypeOfSymbol(property)
const descriptionOptions: SchemaDescriptionOptions = {
typeStr: propertyName,
parentName: tagName,
rawParentName: queryTypeName,
node: property.valueDeclaration,
symbol: property,
nodeType: propertyType,
}
parameters.push(
this.getParameterObject({
name: propertyName,
type: "query",
description: this.getSchemaDescription(descriptionOptions),
required: this.isRequired(property),
schema: this.typeToSchema({
itemType: propertyType,
title: propertyName,
descriptionOptions,
context: "query",
saveSchema: !forUpdate,
}),
})
)
})
return {
queryParameters,
requestSchema,
}
}

const requestTypeArguments =
requestType.typeArguments || requestType.aliasTypeArguments
const requestType = this.checker.getTypeFromTypeNode(
node.parameters[0].type
) as ts.TypeReference
// TODO for now I'll use the type for validatedQuery until
// we have an actual approach to infer query types
const querySymbol = requestType.getProperty("validatedQuery")
if (querySymbol) {
const { shouldAddFields, shouldAddPagination } =
this.shouldAddQueryParams(node)
const queryType = this.checker.getTypeOfSymbol(querySymbol)
const queryTypeName = this.checker.typeToString(queryType)
queryType.getProperties().forEach((property) => {
const propertyName = property.getName()
// if this is a field / pagination query parameter and
// they're not used in the route, don't add them.
if (
(this.FIELD_QUERY_PARAMS.includes(propertyName) &&
!shouldAddFields) ||
(this.PAGINATION_QUERY_PARAMS.includes(propertyName) &&
!shouldAddPagination)
) {
return
}
const propertyType = this.checker.getTypeOfSymbol(property)
const descriptionOptions: SchemaDescriptionOptions = {
typeStr: propertyName,
parentName: tagName,
rawParentName: queryTypeName,
node: property.valueDeclaration,
symbol: property,
nodeType: propertyType,
}
queryParameters.push(
this.getParameterObject({
name: propertyName,
type: "query",
description: this.getSchemaDescription(descriptionOptions),
required: this.isRequired(property),
schema: this.typeToSchema({
itemType: propertyType,
title: propertyName,
descriptionOptions,
context: "query",
saveSchema: !forUpdate,
}),
})
)
})
}

if (requestTypeArguments?.length === 1) {
const zodObjectTypeName = getCorrectZodTypeName({
typeReferenceNode: node.parameters[0].type,
itemType: requestTypeArguments[0],
})
const isQuery = methodName === "get"
const parameterSchema = this.typeToSchema({
itemType: requestTypeArguments[0],
const requestTypeArguments =
requestType.typeArguments || requestType.aliasTypeArguments

if (!requestTypeArguments || requestTypeArguments.length < 2) {
return {
queryParameters,
requestSchema,
}
}

// Not all routes support a second type argument yet,
// so the query param may be passed in the first type argument
const hasQueryParams = requestTypeArguments[1].getProperties().length > 0
// Not all routes support a second type argument yet,
// so we have to support routes that pass the query parameters type
// in the first type argument
const isQuery = methodName === "get"

const zodObjectRequestBodyTypeName = getCorrectZodTypeName({
typeReferenceNode: node.parameters[0].type,
itemType: requestTypeArguments[0],
})
const zodObjectQueryTypeName = getCorrectZodTypeName({
typeReferenceNode: node.parameters[0].type,
itemType: requestTypeArguments[1],
})

const requestBodyParameterSchema = this.typeToSchema({
itemType: requestTypeArguments[0],
descriptionOptions: {
parentName: tagName,
rawParentName: this.checker.typeToString(requestTypeArguments[0]),
},
zodObjectTypeName: zodObjectRequestBodyTypeName,
context: isQuery ? "query" : "request",
saveSchema: !forUpdate,
})
const queryParameterSchema = hasQueryParams
? this.typeToSchema({
itemType: requestTypeArguments[1],
descriptionOptions: {
parentName: tagName,
rawParentName: this.checker.typeToString(requestTypeArguments[0]),
rawParentName: this.checker.typeToString(requestTypeArguments[1]),
},
zodObjectTypeName: zodObjectTypeName,
context: isQuery ? "query" : "request",
zodObjectTypeName: zodObjectQueryTypeName,
context: "query",
saveSchema: !forUpdate,
})
: requestBodyParameterSchema

// If function is a GET function, add the type parameter to the
// query parameters instead of request parameters.
if (isQuery) {
if (parameterSchema.type === "object" && parameterSchema.properties) {
Object.entries(parameterSchema.properties).forEach(
([key, propertySchema]) => {
if ("$ref" in propertySchema) {
return
}
// If function is a GET function, add the type parameter to the
// query parameters instead of request parameters.
if (
(isQuery || hasQueryParams) &&
queryParameterSchema.type === "object" &&
queryParameterSchema.properties
) {
Object.entries(queryParameterSchema.properties).forEach(
([key, propertySchema]) => {
if ("$ref" in propertySchema) {
return
}

// check if parameter is already added
const isAdded = parameters.some((param) => param.name === key)
// check if parameter is already added
const isAdded = queryParameters.some((param) => param.name === key)

if (isAdded) {
return
}

parameters.push(
this.getParameterObject({
name: key,
type: "query",
description: propertySchema.description,
required: parameterSchema.required?.includes(key) || false,
schema: propertySchema,
})
)
}
)
if (isAdded) {
return
}
} else if (methodName !== "delete") {
requestSchema = parameterSchema

queryParameters.push(
this.getParameterObject({
name: key,
type: "query",
description: propertySchema.description,
required: queryParameterSchema.required?.includes(key) || false,
schema: propertySchema,
})
)
}
}
)
}

if (methodName !== "delete" && methodName !== "get") {
requestSchema = requestBodyParameterSchema
}

return {
queryParameters: parameters,
queryParameters,
requestSchema,
}
}
Expand Down

0 comments on commit abdd4c9

Please sign in to comment.