diff --git a/www/utils/packages/docs-generator/src/classes/helpers/knowledge-base-factory.ts b/www/utils/packages/docs-generator/src/classes/helpers/knowledge-base-factory.ts index bd61776e9e..a30fde0e6f 100644 --- a/www/utils/packages/docs-generator/src/classes/helpers/knowledge-base-factory.ts +++ b/www/utils/packages/docs-generator/src/classes/helpers/knowledge-base-factory.ts @@ -523,6 +523,29 @@ class KnowledgeBaseFactory { template: "Pass additional custom data to the API route. This data is passed to the underlying workflow under the `additional_data` parameter.", }, + { + exact: "object", + template: (_, options) => { + if (!options?.rawParentName?.includes("DeleteResponse")) { + return + } + + return "The name of the deleted object." + }, + }, + { + exact: "deleted", + template: (_, options) => { + if ( + !options?.rawParentName?.includes("DeleteResponse") || + !options.parentName + ) { + return + } + + return `Whether the ${singular(options.parentName)} was deleted.` + }, + }, { pattern: /.*/, template(str, options) { @@ -799,6 +822,7 @@ class KnowledgeBaseFactory { : kebabToTitle(splitOasPath[splitOasPath.length - 1]) // retrieve different formatted versions of the entity name for the summary/description const pluralEndingEntityName = pluralize.plural(endingEntityName) + const singularEndingEntityName = pluralize.singular(endingEntityName) const lowerEndingEntityName = pluralEndingEntityName.toLowerCase() const singularLowerEndingEntityName = pluralize.singular(endingEntityName) @@ -808,11 +832,19 @@ class KnowledgeBaseFactory { result.summary = `List ${pluralEndingEntityName}` result.description = `Retrieve a list of ${lowerEndingEntityName} in a ${singularLowerTag}. The ${lowerEndingEntityName} can be filtered by fields like FILTER FIELDS. The ${lowerEndingEntityName} can also be paginated.` } else if (httpMethod === "post") { - result.summary = `Add ${pluralEndingEntityName} to ${singularTag}` - result.description = `Add a list of ${lowerEndingEntityName} to a ${singularLowerTag}.` + result.summary = `Add ${ + isBulk ? pluralEndingEntityName : singularEndingEntityName + } to ${singularTag}` + result.description = isBulk + ? `Add a list of ${lowerEndingEntityName} to a ${singularLowerTag}.` + : `Add a ${singularLowerEndingEntityName} to a ${singularLowerTag}` } else { - result.summary = `Remove ${pluralEndingEntityName} from ${singularTag}` - result.description = `Remove a list of ${lowerEndingEntityName} from a ${singularLowerTag}. This doesn't delete the ${singularLowerEndingEntityName}, only the association between the ${singularLowerEndingEntityName} and the ${singularLowerTag}.` + result.summary = `Remove ${ + isBulk ? pluralEndingEntityName : singularEndingEntityName + } from ${singularTag}` + result.description = isBulk + ? `Remove a list of ${lowerEndingEntityName} from a ${singularLowerTag}.` + : `Remove a ${singularLowerEndingEntityName} from a ${singularLowerTag}.` } } else { // the OAS operation is applied on a single entity that is the main entity (denoted by the tag). diff --git a/www/utils/packages/docs-generator/src/classes/kinds/oas.ts b/www/utils/packages/docs-generator/src/classes/kinds/oas.ts index 44206a4c2f..86caccc806 100644 --- a/www/utils/packages/docs-generator/src/classes/kinds/oas.ts +++ b/www/utils/packages/docs-generator/src/classes/kinds/oas.ts @@ -35,6 +35,7 @@ type SchemaDescriptionOptions = { nodeType?: ts.Type typeStr: string parentName?: string + rawParentName?: string } export type OasArea = "admin" | "store" @@ -954,13 +955,15 @@ class OasKindGenerator extends FunctionKindGenerator { // 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) { + if (querySymbol && this.shouldAddQueryParams(node)) { const queryType = this.checker.getTypeOfSymbol(querySymbol) + const queryTypeName = this.checker.typeToString(queryType) queryType.getProperties().forEach((property) => { const propertyType = this.checker.getTypeOfSymbol(property) const descriptionOptions: SchemaDescriptionOptions = { typeStr: property.getName(), parentName: tagName, + rawParentName: queryTypeName, node: property.valueDeclaration, symbol: property, nodeType: propertyType, @@ -993,6 +996,7 @@ class OasKindGenerator extends FunctionKindGenerator { itemType: requestTypeArguments[0], descriptionOptions: { parentName: tagName, + rawParentName: this.checker.typeToString(requestTypeArguments[0]), }, zodObjectTypeName: zodObjectTypeName, }) @@ -1095,6 +1099,7 @@ class OasKindGenerator extends FunctionKindGenerator { itemType: responseTypeArguments[0], descriptionOptions: { parentName: tagName, + rawParentName: this.checker.typeToString(responseTypeArguments[0]), }, zodObjectTypeName: getCorrectZodTypeName({ typeReferenceNode: node.parameters[1].type, @@ -1390,8 +1395,9 @@ class OasKindGenerator extends FunctionKindGenerator { if (this.isRequired(property)) { requiredProperties.push(property.name) } + const propertyType = this.checker.getTypeOfSymbol(property) properties[property.name] = this.typeToSchema({ - itemType: this.checker.getTypeOfSymbol(property), + itemType: propertyType, level: level + 1, title: property.name, descriptionOptions: { @@ -1453,7 +1459,7 @@ class OasKindGenerator extends FunctionKindGenerator { node, nodeType, typeStr, - parentName, + ...templateOptions }: SchemaDescriptionOptions): string { if (!symbol && !node && !nodeType) { // if none of the associated symbol, node, or type are provided, @@ -1462,9 +1468,7 @@ class OasKindGenerator extends FunctionKindGenerator { return ( this.knowledgeBaseFactory.tryToGetOasSchemaDescription({ str: typeStr, - templateOptions: { - parentName, - }, + templateOptions, }) || SUMMARY_PLACEHOLDER ) } @@ -1882,66 +1886,54 @@ class OasKindGenerator extends FunctionKindGenerator { getAssociatedWorkflow(node: FunctionNode): string | undefined { let workflow: string | undefined - if ( - (!ts.isFunctionDeclaration(node) && !ts.isArrowFunction(node)) || - !node.body || - !ts.isBlock(node.body) - ) { + if (!ts.isFunctionDeclaration(node) && !ts.isArrowFunction(node)) { return } const sourceFile = node.getSourceFile() - const fileLocalSymbols: Map = - "locals" in sourceFile - ? (sourceFile.locals as Map) - : new Map() - if (!fileLocalSymbols.size) { + // if a source file doesn't have imports, then it's assumed that it's not using workflows. + if (!("imports" in sourceFile) || !Array.isArray(sourceFile.imports)) { return } - node.body.statements.some((statement) => { - let awaitExpression: ts.AwaitExpression | undefined + // retrieve workflows imported from `@medusajs/core-flows` + // since there could be multiple import statements from the + // same package, put them in an array + const coreFlowsImports: ts.ImportClause[] = [] + ;(sourceFile.imports as ts.Node[]).forEach((importNode) => { if ( - ts.isVariableStatement(statement) && - statement.declarationList.declarations[0].initializer && - ts.isAwaitExpression( - statement.declarationList.declarations[0].initializer - ) + !importNode.parent || + !ts.isImportDeclaration(importNode.parent) || + !importNode.parent.importClause?.namedBindings || + importNode.getText() !== `"@medusajs/core-flows"` ) { - awaitExpression = statement.declarationList.declarations[0].initializer - } else if (ts.isAwaitExpression(statement)) { - awaitExpression = statement + return } - if ( - !awaitExpression || - !ts.isCallExpression(awaitExpression.expression) || - !ts.isPropertyAccessExpression(awaitExpression.expression.expression) || - !awaitExpression.expression.expression.name.getText().startsWith("run") - ) { - return false - } + coreFlowsImports.push(importNode.parent.importClause) + }) - const fullExpressionText = awaitExpression.expression.getText() - const parenIndex = fullExpressionText.indexOf("(") - const dotIndex = fullExpressionText.indexOf(".") - const cutOffIndex = - parenIndex !== -1 && dotIndex === -1 - ? parenIndex - : parenIndex === -1 && dotIndex !== -1 - ? dotIndex - : parenIndex === -1 && dotIndex === -1 - ? fullExpressionText.length - : Math.min(parenIndex, dotIndex) - const expressionName = fullExpressionText.substring(0, cutOffIndex) + // if no imports found from `@medusajs/core-flows`, return + if (!coreFlowsImports.length) { + return + } - if (!fileLocalSymbols.has(expressionName)) { - return false - } + // check if any of the imported vars are used in the function node + // const fileWorkflowImports: Map = new Map() + const fnText = node.getText() + coreFlowsImports.forEach((coreFlowsImport) => { + coreFlowsImport.namedBindings?.forEachChild((childImport) => { + if (!ts.isImportSpecifier(childImport) || workflow) { + return + } - workflow = expressionName - return true + const workflowName = childImport.name.getText() + + if (fnText.includes(workflowName)) { + workflow = workflowName + } + }) }) return workflow @@ -2031,6 +2023,17 @@ class OasKindGenerator extends FunctionKindGenerator { writeFileSync(areaYamlPath, stringify(areaYaml)) } } + + shouldAddQueryParams(node: FunctionNode): boolean { + const queryParamsUsageIndicators = [ + `req.filterableFields`, + `req.remoteQueryConfig`, + ] + const fnText = node.getText() + return queryParamsUsageIndicators.some((indicator) => + fnText.includes(indicator) + ) + } } export default OasKindGenerator diff --git a/www/utils/packages/docs-generator/src/utils/format-oas.ts b/www/utils/packages/docs-generator/src/utils/format-oas.ts index 8e7522881e..7113001856 100644 --- a/www/utils/packages/docs-generator/src/utils/format-oas.ts +++ b/www/utils/packages/docs-generator/src/utils/format-oas.ts @@ -13,8 +13,7 @@ export default function formatOas( oas: OpenApiOperation | OpenApiSchema, oasPrefix: string ) { - return `* ${oasPrefix}${DOCBLOCK_NEW_LINE}${stringify(oas).replaceAll( - "\n", - DOCBLOCK_NEW_LINE - )}${DOCBLOCK_END_LINE}` + return `* ${oasPrefix}${DOCBLOCK_NEW_LINE}${stringify(oas, { + lineWidth: 200, + }).replaceAll("\n", DOCBLOCK_NEW_LINE)}${DOCBLOCK_END_LINE}` }