docs: document locks for nested workflows (#14130)

* docs: document locks for nested workflows

* smal text change

* fix build error
This commit is contained in:
Shahed Nasser
2025-11-26 15:36:58 +02:00
committed by GitHub
parent 76660fb6cc
commit c1ede88a7e
53 changed files with 712 additions and 208 deletions

View File

@@ -85,6 +85,7 @@ import eventsListingHelper from "./resources/helpers/events-listing.js"
import workflowEventsHelper from "./resources/helpers/workflow-events.js"
import getAllChildrenHelper from "./resources/helpers/get-all-children.js"
import reflectionBadgesHelper from "./resources/helpers/reflection-badges.js"
import workflowNotes from "./resources/helpers/workflow-notes.js"
import { MarkdownTheme } from "./theme.js"
import { getDirname } from "utils"
@@ -194,11 +195,12 @@ export function registerHelpers(theme: MarkdownTheme) {
signatureCommentHelper()
versionHelper()
sourceCodeLinkHelper()
workflowExamplesHelper()
workflowExamplesHelper(theme)
stepExamplesHelper()
ifEventsReferenceHelper(theme)
eventsListingHelper()
workflowEventsHelper()
getAllChildrenHelper(theme)
reflectionBadgesHelper()
workflowNotes(theme)
}

View File

@@ -1,68 +1,22 @@
import Handlebars from "handlebars"
import { MarkdownTheme } from "../../theme.js"
import { stringify } from "yaml"
import { replaceTemplateVariables } from "../../utils/reflection-template-strings.js"
import { Reflection } from "typedoc"
import { FrontmatterData, Tag } from "types"
import { getTagComments, getTagsAsArray } from "utils"
import { getPageFrontmatter } from "../../utils/frontmatter.js"
export default function (theme: MarkdownTheme) {
Handlebars.registerHelper("frontmatter", function (this: Reflection) {
const { frontmatterData } = theme.getFormattingOptionsForLocation()
if (!frontmatterData) {
return ""
}
// format frontmatter data in case it has any template variables
const resolvedFrontmatter = resolveFrontmatterVariables(
const resolvedFrontmatter = getPageFrontmatter({
frontmatterData,
this
)
// check if reflection has an `@tags` tag
const tagsComment = getTagComments(this)
if (tagsComment?.length && !("tags" in resolvedFrontmatter)) {
resolvedFrontmatter["tags"] = []
}
tagsComment?.forEach((tag) => {
const tagContent = getTagsAsArray(tag)
resolvedFrontmatter["tags"]?.push(...tagContent)
reflection: this,
})
if (resolvedFrontmatter["tags"]?.length) {
resolvedFrontmatter["tags"] = getUniqueTags(resolvedFrontmatter["tags"])
if (!resolvedFrontmatter) {
return ""
}
return `---\n${stringify(resolvedFrontmatter).trim()}\n---\n\n`
})
}
function resolveFrontmatterVariables(
frontmatterData: FrontmatterData,
reflection: Reflection
): FrontmatterData {
const tempFrontmatterData: FrontmatterData = JSON.parse(
JSON.stringify(frontmatterData)
)
Object.keys(tempFrontmatterData).forEach((key) => {
const value = tempFrontmatterData[key]
if (!value || typeof value !== "string") {
return
}
tempFrontmatterData[key] = replaceTemplateVariables(reflection, value)
})
return tempFrontmatterData
}
function getUniqueTags(tags: Tag[]): Tag[] {
const tagsMap = new Map<string, Tag>()
tags.forEach((tag) => {
const tagName = typeof tag === "string" ? tag : tag.name
tagsMap.set(tagName, tag)
})
return Array.from(tagsMap.values())
}

View File

@@ -2,11 +2,24 @@ import Handlebars from "handlebars"
import { DeclarationReflection, SignatureReflection } from "typedoc"
import { getReflectionTypeFakeValueStr, getWorkflowInputType } from "utils"
import beautifyCode from "../../utils/beautify-code.js"
import { MarkdownTheme } from "../../theme.js"
import { getPageFrontmatter } from "../../utils/frontmatter.js"
export default function () {
export default function (theme: MarkdownTheme) {
Handlebars.registerHelper(
"workflowExamples",
function (this: SignatureReflection): string {
const frontmatter = getPageFrontmatter({
frontmatterData:
theme.getFormattingOptionsForLocation().frontmatterData,
reflection: this,
})
const hasLocking =
frontmatter?.tags?.some((tag) => {
return typeof tag === "string"
? tag === "locking"
: tag.name === "locking"
}) ?? false
const workflowReflection = this.parent
const exampleStr: string[] = []
@@ -19,6 +32,7 @@ export default function () {
getExecutionCodeTabs({
exampleCode: generateWorkflowExample(workflowReflection),
workflowName: workflowReflection.name,
hasLocking,
})
)
} else {
@@ -42,6 +56,7 @@ export default function () {
getExecutionCodeTabs({
exampleCode: part.text,
workflowName: workflowReflection.name,
hasLocking,
})
)
})
@@ -58,9 +73,11 @@ export default function () {
function getExecutionCodeTabs({
exampleCode,
workflowName,
hasLocking,
}: {
exampleCode: string
workflowName: string
hasLocking: boolean
}): string {
exampleCode = exampleCode.replace("```ts\n", "").replace("\n```", "")
@@ -139,12 +156,14 @@ import { ${workflowName} } from "@medusajs/medusa/core-flows"
const myWorkflow = createWorkflow(
"my-workflow",
() => {
() => {${hasLocking ? "\n // Acquire lock from nested workflow here" : ""}
${exampleCode
.replace(`{ result }`, "result")
.replace(`await `, "")
.replace(`(container)`, "")
.replace(".run(", ".runAsStep(")}
.replace(".run(", ".runAsStep(")}${
hasLocking ? "\n // Release lock here" : ""
}
}
)`)}
\`\`\`

View File

@@ -0,0 +1,36 @@
import Handlebars from "handlebars"
import { SignatureReflection } from "typedoc"
import { MarkdownTheme } from "../../theme.js"
import { getPageFrontmatter } from "../../utils/frontmatter.js"
export default function (theme: MarkdownTheme) {
Handlebars.registerHelper(
"workflowNotes",
function (this: SignatureReflection): string {
const notes: string[] = []
const frontmatter = getPageFrontmatter({
frontmatterData:
theme.getFormattingOptionsForLocation().frontmatterData,
reflection: this,
})
const hasLocking =
frontmatter?.tags?.some((tag) => {
return typeof tag === "string"
? tag === "locking"
: tag.name === "locking"
}) ?? false
if (hasLocking) {
notes.push(
`:::note
If you use this workflow in another, you must acquire a lock before running it and release the lock after. Learn more in the [Locking Operations in Workflows](https://docs.medusajs.com/learn/fundamentals/workflows/locks#locks-in-nested-workflows) guide.
:::`
)
}
return notes.join("\n\n")
}
)
}

View File

@@ -6,6 +6,8 @@
{{{version this}}}
{{{workflowNotes this}}}
{{/if}}
{{{sourceCodeLink}}}

View File

@@ -1,46 +0,0 @@
import Handlebars from "handlebars"
import { PageEvent } from "typedoc"
export interface FrontMatterVars {
[key: string]: string | number | boolean
}
/**
* Prepends YAML block to a string
* @param contents - the string to prepend
* @param vars - object of required front matter variables
*/
export const prependYAML = (contents: string, vars: FrontMatterVars) => {
return contents
.replace(/^/, toYAML(vars) + "\n\n")
.replace(/[\r\n]{3,}/g, "\n\n")
}
/**
* Returns the page title as rendered in the document h1(# title)
* @param page
*/
export const getPageTitle = (page: PageEvent) => {
return Handlebars.helpers.reflectionTitle.call(page, false)
}
/**
* Converts YAML object to a YAML string
* @param vars
*/
const toYAML = (vars: FrontMatterVars) => {
const yaml = `---
${Object.entries(vars)
.map(
([key, value]) =>
`${key}: ${
typeof value === "string" ? `"${escapeString(value)}"` : value
}`
)
.join("\n")}
---`
return yaml
}
// prettier-ignore
const escapeString = (str: string) => str.replace(/"/g, "\\\"")

View File

@@ -0,0 +1,67 @@
import { Reflection } from "typedoc"
import { FrontmatterData, Tag } from "types"
import { getTagComments, getTagsAsArray } from "utils"
import { replaceTemplateVariables } from "./reflection-template-strings.js"
export function getPageFrontmatter({
frontmatterData,
reflection,
}: {
frontmatterData: FrontmatterData | undefined
reflection: Reflection
}): FrontmatterData | undefined {
if (!frontmatterData) {
return
}
// format frontmatter data in case it has any template variables
const resolvedFrontmatter = resolveFrontmatterVariables(
frontmatterData,
reflection
)
// check if reflection has an `@tags` tag
const tagsComment = getTagComments(reflection)
if (tagsComment?.length && !("tags" in resolvedFrontmatter)) {
resolvedFrontmatter["tags"] = []
}
tagsComment?.forEach((tag) => {
const tagContent = getTagsAsArray(tag)
resolvedFrontmatter["tags"]?.push(...tagContent)
})
if (resolvedFrontmatter["tags"]?.length) {
resolvedFrontmatter["tags"] = getUniqueTags(resolvedFrontmatter["tags"])
}
return resolvedFrontmatter
}
function resolveFrontmatterVariables(
frontmatterData: FrontmatterData,
reflection: Reflection
): FrontmatterData {
const tempFrontmatterData: FrontmatterData = JSON.parse(
JSON.stringify(frontmatterData)
)
Object.keys(tempFrontmatterData).forEach((key) => {
const value = tempFrontmatterData[key]
if (!value || typeof value !== "string") {
return
}
tempFrontmatterData[key] = replaceTemplateVariables(reflection, value)
})
return tempFrontmatterData
}
function getUniqueTags(tags: Tag[]): Tag[] {
const tagsMap = new Map<string, Tag>()
tags.forEach((tag) => {
const tagName = typeof tag === "string" ? tag : tag.name
tagsMap.set(tagName, tag)
})
return Array.from(tagsMap.values())
}