Skip to content

Commit

Permalink
docs-util: add examples generator for workflows and steps (#10914)
Browse files Browse the repository at this point in the history
* initial changes

* docs-util: generate examples for workflows and steps
  • Loading branch information
shahednasser authored Jan 10, 2025
1 parent e82645b commit c591545
Show file tree
Hide file tree
Showing 17 changed files with 810 additions and 142 deletions.
4 changes: 4 additions & 0 deletions www/apps/resources/components/MDXComponents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
TypeList,
WorkflowDiagram,
SourceCodeLink,
CodeTabs,
CodeTab,
} from "docs-ui"
import { CommerceModuleSections } from "../CommerceModuleSections"

Expand All @@ -15,6 +17,8 @@ const MDXComponents: MDXComponentsType = {
WorkflowDiagram,
CommerceModuleSections,
SourceCodeLink,
CodeTabs,
CodeTab,
}

export default MDXComponents
2 changes: 0 additions & 2 deletions www/utils/packages/docs-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"type": "module",
"exports": "./dist/index.js",
"dependencies": {
"@faker-js/faker": "^8.4.0",
"@octokit/core": "^5.0.2",
"chalk": "^5.4.1",
"commander": "^11.1.0",
Expand All @@ -27,7 +26,6 @@
"openai": "^4.29.1",
"openapi-types": "^12.1.3",
"pluralize": "^8.0.0",
"prettier": "^3.2.4",
"ts-node": "^10.9.1",
"typescript": "^5.6.2",
"utils": "*",
Expand Down
73 changes: 10 additions & 63 deletions www/utils/packages/docs-generator/src/classes/examples/oas.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { faker } from "@faker-js/faker"
import { OpenAPIV3 } from "openapi-types"
import { OasArea } from "../kinds/oas.js"
import { CodeSample } from "../../types/index.js"
import { capitalize, kebabToCamel, wordsToCamel, wordsToKebab } from "utils"
import {
capitalize,
getFakeStrValue,
kebabToCamel,
wordsToCamel,
wordsToKebab,
} from "utils"
import { API_ROUTE_PARAM_REGEX } from "../../constants.js"

type CodeSampleData = Omit<CodeSample, "source">
Expand Down Expand Up @@ -274,7 +279,7 @@ class OasExamplesGenerator {
? this.getSchemaRequiredData(
typedChildProp as OpenAPIV3.SchemaObject
)
: this.getFakeValue({
: getFakeStrValue({
name: childName,
type: typedChildProp.type,
format: typedChildProp.format,
Expand All @@ -296,7 +301,7 @@ class OasExamplesGenerator {
? this.getSchemaRequiredData(
property.items as OpenAPIV3.SchemaObject
)
: this.getFakeValue({
: getFakeStrValue({
name: propertyName,
type: propertyItems.type,
format: propertyItems.format,
Expand All @@ -305,7 +310,7 @@ class OasExamplesGenerator {
}
} else if (property.type) {
// retrieve fake value for all other types
value = this.getFakeValue({
value = getFakeStrValue({
name: propertyName,
type: property.type,
format: property.format,
Expand All @@ -320,64 +325,6 @@ class OasExamplesGenerator {

return data
}

/**
* Retrieve the fake value of a property. The value is used in examples.
*
* @param param0 - The property's details
* @returns The fake value
*/
getFakeValue({
name,
type,
format,
}: {
/**
* The name of the property. It can help when generating the fake value.
* For example, if the name is `id`, the fake value generated will be of the format `id_<randomstring>`.
*/
name: string
/**
* The type of the property.
*/
type: OpenAPIV3.NonArraySchemaObjectType | "array"
/**
* The OAS format of the property. For example, `date-time`.
*/
format?: string
}): unknown {
let value: unknown

switch (true) {
case type === "string" && format === "date-time":
value = faker.date.future().toISOString()
break
case type === "boolean":
value = faker.datatype.boolean()
break
case type === "integer" || type === "number":
value = faker.number.int()
break
case type === "array":
value = []
break
case type === "string":
value = faker.helpers
.mustache(`{{${name}}}`, {
id: () =>
`id_${faker.string.alphanumeric({
length: { min: 10, max: 20 },
})}`,
name: () => faker.person.firstName(),
email: () => faker.internet.email(),
password: () => faker.internet.password({ length: 8 }),
currency: () => faker.finance.currencyCode(),
})
.replace(`{{${name}}}`, "{value}")
}

return value !== undefined ? value : "{value}"
}
}

export default OasExamplesGenerator
28 changes: 2 additions & 26 deletions www/utils/packages/docs-generator/src/classes/helpers/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import path from "path"
import dirname from "../../utils/dirname.js"
import { minimatch } from "minimatch"
import { existsSync } from "fs"
import * as prettier from "prettier"
import getRelativePaths from "../../utils/get-relative-paths.js"
import { formatWithPrettier } from "utils"

/**
* A class used to apply formatting to files using ESLint and other formatting options.
Expand Down Expand Up @@ -174,10 +174,7 @@ class Formatter {
content: string,
fileName: string
): Promise<string> {
const prettifiedContent = await this.formatStrWithPrettier(
content,
fileName
)
const prettifiedContent = await formatWithPrettier(content, fileName)
const relevantConfig = await this.getESLintOverridesConfigForFile(fileName)

const eslint = new ESLint({
Expand All @@ -203,27 +200,6 @@ class Formatter {
return newContent
}

/**
* Format a file's content with prettier.
*
* @param content - The content to format.
* @param fileName - The name of the file the content belongs to.
* @returns The formatted content
*/
async formatStrWithPrettier(
content: string,
fileName: string
): Promise<string> {
// load config of the file
const prettierConfig = (await prettier.resolveConfig(fileName)) || undefined

if (prettierConfig && !prettierConfig.parser) {
prettierConfig.parser = "babel-ts"
}

return await prettier.format(content, prettierConfig)
}

/**
* Applies all formatting types to a string.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"typedoc": "0.27.x"
},
"devDependencies": {
"@types/js-beautify": "^1.14.3",
"@types/node": "^20.12.10",
"copyfiles": "^2.4.1",
"typedoc": "^0.27.5",
Expand All @@ -36,6 +37,7 @@
],
"dependencies": {
"handlebars": "^4.7.8",
"js-beautify": "^1.15.1",
"utils": "*"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ import ifMemberShowTitleHelper from "./resources/helpers/if-member-show-title.js
import signatureCommentHelper from "./resources/helpers/signature-comment.js"
import versionHelper from "./resources/helpers/version.js"
import sourceCodeLinkHelper from "./resources/helpers/source-code-link.js"
import workflowExamplesHelper from "./resources/helpers/workflow-examples.js"
import stepExamplesHelper from "./resources/helpers/step-examples.js"
import { MarkdownTheme } from "./theme.js"
import { getDirname } from "utils"

Expand Down Expand Up @@ -187,4 +189,6 @@ export function registerHelpers(theme: MarkdownTheme) {
signatureCommentHelper()
versionHelper()
sourceCodeLinkHelper()
workflowExamplesHelper()
stepExamplesHelper()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Handlebars from "handlebars"
import { DeclarationReflection, SignatureReflection } from "typedoc"
import { getReflectionTypeFakeValueStr, getStepInputType } from "utils"
import pkg from "js-beautify"

const { js_beautify } = pkg

export default function () {
Handlebars.registerHelper(
"stepExamples",
function (this: SignatureReflection): string {
const stepReflection = this.parent

const exampleTags = stepReflection.comment?.blockTags.filter(
(tag) => tag.tag === "@example"
)

if (exampleTags?.length) {
return Handlebars.helpers.example(stepReflection)
}

return generateStepExample(stepReflection)
}
)
}

function generateStepExample(stepReflection: DeclarationReflection): string {
if (!stepReflection.signatures?.length) {
return ""
}
const inputType = getStepInputType(stepReflection.signatures[0])
const inputStr = inputType
? `${getReflectionTypeFakeValueStr({
reflectionType: inputType,
name: "",
})}`
: ""

// generate example
return `
\`\`\`ts title="src/workflows/my-workflow.ts"
${js_beautify(
`import { createWorkflow } from "@medusajs/framework/workflows-sdk"
import { ${stepReflection.name} } from "@medusajs/medusa/core-flows"
const myWorkflow = createWorkflow(
"my-workflow",
() => {
const data = ${stepReflection.name}(${inputStr})
}
)`,
{
indent_size: 2,
brace_style: "preserve-inline",
wrap_line_length: 80,
}
)}
\`\`\`
`
}
Loading

0 comments on commit c591545

Please sign in to comment.