docs-util: add support for workflows in markdown theme (#8485)
* add template for workflows * initial changes * added support for parallel steps * added support for when * added merge options * fix merge options * fix to tooltip * clean up * remove redirects * fixes * theme fixes + added merge options * generate hook examples + fixes * changed namespaces * add custom autogenerator * change type of additional data
This commit is contained in:
@@ -5,6 +5,7 @@ export * from "./local-links.js"
|
||||
export * from "./page-number.js"
|
||||
export * from "./resolve-admonitions.js"
|
||||
export * from "./type-list-link-fixer.js"
|
||||
export * from "./workflow-diagram-link-fixer.js"
|
||||
|
||||
export * from "./utils/fix-link.js"
|
||||
export * from "./utils/get-file-slug.js"
|
||||
|
||||
@@ -1,126 +1,9 @@
|
||||
import path from "path"
|
||||
import { Transformer } from "unified"
|
||||
import {
|
||||
ExpressionJsVar,
|
||||
TypeListLinkFixerOptions,
|
||||
UnistNodeWithData,
|
||||
UnistTree,
|
||||
} from "./types/index.js"
|
||||
import { FixLinkOptions, fixLinkUtil } from "./index.js"
|
||||
import getAttribute from "./utils/get-attribute.js"
|
||||
import { estreeToJs } from "./utils/estree-to-js.js"
|
||||
import {
|
||||
isExpressionJsVarLiteral,
|
||||
isExpressionJsVarObj,
|
||||
} from "./utils/expression-is-utils.js"
|
||||
|
||||
const LINK_REGEX = /\[(.*?)\]\((?<link>.*?)\)/gm
|
||||
|
||||
function matchLinks(
|
||||
str: string,
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">
|
||||
) {
|
||||
let linkMatches
|
||||
while ((linkMatches = LINK_REGEX.exec(str)) !== null) {
|
||||
if (!linkMatches.groups?.link) {
|
||||
return
|
||||
}
|
||||
|
||||
const newUrl = fixLinkUtil({
|
||||
...linkOptions,
|
||||
linkedPath: linkMatches.groups.link,
|
||||
})
|
||||
|
||||
str = str.replace(linkMatches.groups.link, newUrl)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
function traverseTypes(
|
||||
types: ExpressionJsVar[] | ExpressionJsVar,
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">
|
||||
) {
|
||||
if (Array.isArray(types)) {
|
||||
types.forEach((item) => traverseTypes(item, linkOptions))
|
||||
} else if (isExpressionJsVarLiteral(types)) {
|
||||
types.original.value = matchLinks(
|
||||
types.original.value as string,
|
||||
linkOptions
|
||||
)
|
||||
types.original.raw = JSON.stringify(types.original.value)
|
||||
} else {
|
||||
Object.values(types).forEach((value) => {
|
||||
if (Array.isArray(value) || isExpressionJsVarObj(value)) {
|
||||
return traverseTypes(value, linkOptions)
|
||||
}
|
||||
|
||||
if (!isExpressionJsVarLiteral(value)) {
|
||||
return
|
||||
}
|
||||
|
||||
value.original.value = matchLinks(
|
||||
value.original.value as string,
|
||||
linkOptions
|
||||
)
|
||||
value.original.raw = JSON.stringify(value.original.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
import { ComponentLinkFixerOptions } from "./types/index.js"
|
||||
import { componentLinkFixer } from "./utils/component-link-fixer.js"
|
||||
|
||||
export function typeListLinkFixerPlugin(
|
||||
options?: TypeListLinkFixerOptions
|
||||
options?: ComponentLinkFixerOptions
|
||||
): Transformer {
|
||||
const { filePath, basePath } = options || {}
|
||||
return async (tree, file) => {
|
||||
if (!file.cwd) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!file.history.length) {
|
||||
if (!filePath) {
|
||||
return
|
||||
}
|
||||
|
||||
file.history.push(filePath)
|
||||
}
|
||||
|
||||
const { visit } = await import("unist-util-visit")
|
||||
|
||||
const currentPageFilePath = file.history[0].replace(
|
||||
`/${path.basename(file.history[0])}`,
|
||||
""
|
||||
)
|
||||
const appsPath = basePath || path.join(file.cwd, "app")
|
||||
visit(tree as UnistTree, "mdxJsxFlowElement", (node: UnistNodeWithData) => {
|
||||
if (node.name !== "TypeList") {
|
||||
return
|
||||
}
|
||||
|
||||
const typesAttribute = getAttribute(node, "types")
|
||||
|
||||
if (
|
||||
!typesAttribute ||
|
||||
typeof typesAttribute.value === "string" ||
|
||||
!typesAttribute.value.data?.estree
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const linkOptions = {
|
||||
currentPageFilePath,
|
||||
appsPath,
|
||||
}
|
||||
|
||||
// let newItems: Record<string, unknown>[]
|
||||
|
||||
const typesJsVar = estreeToJs(typesAttribute.value.data.estree)
|
||||
|
||||
if (!typesJsVar) {
|
||||
return
|
||||
}
|
||||
|
||||
traverseTypes(typesJsVar, linkOptions)
|
||||
})
|
||||
}
|
||||
return componentLinkFixer("TypeList", "types", options)
|
||||
}
|
||||
|
||||
@@ -118,9 +118,12 @@ export declare type CrossProjectLinksOptions = {
|
||||
useBaseUrl?: boolean
|
||||
}
|
||||
|
||||
export declare type TypeListLinkFixerOptions = {
|
||||
export declare type ComponentLinkFixerLinkType = "md" | "value"
|
||||
|
||||
export declare type ComponentLinkFixerOptions = {
|
||||
filePath?: string
|
||||
basePath?: string
|
||||
checkLinksType: ComponentLinkFixerLinkType
|
||||
}
|
||||
|
||||
export declare type LocalLinkOptions = {
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import path from "path"
|
||||
import { Transformer } from "unified"
|
||||
import {
|
||||
ComponentLinkFixerLinkType,
|
||||
ExpressionJsVar,
|
||||
UnistNodeWithData,
|
||||
UnistTree,
|
||||
} from "../types/index.js"
|
||||
import { FixLinkOptions, fixLinkUtil } from "../index.js"
|
||||
import getAttribute from "../utils/get-attribute.js"
|
||||
import { estreeToJs } from "../utils/estree-to-js.js"
|
||||
import {
|
||||
isExpressionJsVarLiteral,
|
||||
isExpressionJsVarObj,
|
||||
} from "../utils/expression-is-utils.js"
|
||||
import { ComponentLinkFixerOptions } from "../types/index.js"
|
||||
|
||||
const MD_LINK_REGEX = /\[(.*?)\]\((?<link>.*?)\)/gm
|
||||
const VALUE_LINK_REGEX = /^(![a-z]+!|\.)/gm
|
||||
|
||||
function matchMdLinks(
|
||||
str: string,
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">
|
||||
) {
|
||||
let linkMatches
|
||||
while ((linkMatches = MD_LINK_REGEX.exec(str)) !== null) {
|
||||
if (!linkMatches.groups?.link) {
|
||||
return
|
||||
}
|
||||
|
||||
const newUrl = fixLinkUtil({
|
||||
...linkOptions,
|
||||
linkedPath: linkMatches.groups.link,
|
||||
})
|
||||
|
||||
str = str.replace(linkMatches.groups.link, newUrl)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
function matchValueLink(
|
||||
str: string,
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">
|
||||
) {
|
||||
if (!VALUE_LINK_REGEX.exec(str)) {
|
||||
return str
|
||||
}
|
||||
|
||||
return fixLinkUtil({
|
||||
...linkOptions,
|
||||
linkedPath: str,
|
||||
})
|
||||
}
|
||||
|
||||
function traverseJsVar(
|
||||
item: ExpressionJsVar[] | ExpressionJsVar,
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">,
|
||||
checkLinksType: ComponentLinkFixerLinkType
|
||||
) {
|
||||
const linkFn = checkLinksType === "md" ? matchMdLinks : matchValueLink
|
||||
if (Array.isArray(item)) {
|
||||
item.forEach((item) => traverseJsVar(item, linkOptions, checkLinksType))
|
||||
} else if (isExpressionJsVarLiteral(item)) {
|
||||
item.original.value = linkFn(item.original.value as string, linkOptions)
|
||||
item.original.raw = JSON.stringify(item.original.value)
|
||||
} else {
|
||||
Object.values(item).forEach((value) => {
|
||||
if (Array.isArray(value) || isExpressionJsVarObj(value)) {
|
||||
return traverseJsVar(value, linkOptions, checkLinksType)
|
||||
}
|
||||
|
||||
if (!isExpressionJsVarLiteral(value)) {
|
||||
return
|
||||
}
|
||||
|
||||
value.original.value = linkFn(value.original.value as string, linkOptions)
|
||||
value.original.raw = JSON.stringify(value.original.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function componentLinkFixer(
|
||||
componentName: string,
|
||||
attributeName: string,
|
||||
options?: ComponentLinkFixerOptions
|
||||
): Transformer {
|
||||
const { filePath, basePath, checkLinksType = "md" } = options || {}
|
||||
return async (tree, file) => {
|
||||
if (!file.cwd) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!file.history.length) {
|
||||
if (!filePath) {
|
||||
return
|
||||
}
|
||||
|
||||
file.history.push(filePath)
|
||||
}
|
||||
|
||||
const { visit } = await import("unist-util-visit")
|
||||
|
||||
const currentPageFilePath = file.history[0].replace(
|
||||
`/${path.basename(file.history[0])}`,
|
||||
""
|
||||
)
|
||||
const appsPath = basePath || path.join(file.cwd, "app")
|
||||
visit(tree as UnistTree, "mdxJsxFlowElement", (node: UnistNodeWithData) => {
|
||||
if (node.name !== componentName) {
|
||||
return
|
||||
}
|
||||
|
||||
const workflowAttribute = getAttribute(node, attributeName)
|
||||
|
||||
if (
|
||||
!workflowAttribute ||
|
||||
typeof workflowAttribute.value === "string" ||
|
||||
!workflowAttribute.value.data?.estree
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const linkOptions = {
|
||||
currentPageFilePath,
|
||||
appsPath,
|
||||
}
|
||||
|
||||
const itemJsVar = estreeToJs(workflowAttribute.value.data.estree)
|
||||
|
||||
if (!itemJsVar) {
|
||||
return
|
||||
}
|
||||
|
||||
traverseJsVar(itemJsVar, linkOptions, checkLinksType)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Transformer } from "unified"
|
||||
import { ComponentLinkFixerOptions } from "./types/index.js"
|
||||
import { componentLinkFixer } from "./utils/component-link-fixer.js"
|
||||
|
||||
export function workflowDiagramLinkFixerPlugin(
|
||||
options?: ComponentLinkFixerOptions
|
||||
): Transformer {
|
||||
return componentLinkFixer("WorkflowDiagram", "workflow", options)
|
||||
}
|
||||
Reference in New Issue
Block a user