diff --git a/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts b/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts index 0bbce308d3..804dea5da6 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts @@ -16,6 +16,22 @@ const customOptions: Record> = { name: "core-flows", plugin: ["typedoc-plugin-workflows"], enableWorkflowsPlugins: true, + enableNamespaceGenerator: true, + // @ts-expect-error there's a typing issue in typedoc + generateNamespaces: [ + { + name: "Workflows", + description: + "Workflows listed here are created by Medusa and can be imported from `@medusajs/core-flows`.", + pathPattern: "**/packages/core/core-flows/**/workflows/**", + }, + { + name: "Steps", + description: + "Steps listed here are created by Medusa and can be imported from `@medusajs/core-flows`.", + pathPattern: "**/packages/core/core-flows/**/steps/**", + }, + ], }), "auth-provider": getOptions({ entryPointPath: "packages/core/utils/src/auth/abstract-auth-provider.ts", @@ -31,7 +47,6 @@ const customOptions: Record> = { ], tsConfigName: "utils.json", name: "dml", - generateNamespaces: true, }), file: getOptions({ entryPointPath: "packages/core/utils/src/file/abstract-file-provider.ts", diff --git a/www/utils/packages/typedoc-plugin-custom/package.json b/www/utils/packages/typedoc-plugin-custom/package.json index f2ba0931d2..1a1c629a29 100644 --- a/www/utils/packages/typedoc-plugin-custom/package.json +++ b/www/utils/packages/typedoc-plugin-custom/package.json @@ -36,6 +36,7 @@ "dependencies": { "eslint": "^8.53.0", "glob": "^10.3.10", + "minimatch": "^10.0.1", "utils": "*", "yaml": "^2.3.3" } diff --git a/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts b/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts index 7015ed14e9..a86d86650d 100644 --- a/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts +++ b/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts @@ -1,277 +1,81 @@ +import { minimatch } from "minimatch" import { Application, Comment, - CommentDisplayPart, - CommentTag, - Context, Converter, DeclarationReflection, ParameterType, - Reflection, - ReflectionCategory, ReflectionKind, } from "typedoc" +import { NamespaceGenerateDetails } from "types" -type PluginOptions = { - generateNamespaces: boolean - parentNamespace: string - namePrefix: string -} +export function load(app: Application) { + app.options.addDeclaration({ + name: "enableNamespaceGenerator", + type: ParameterType.Boolean, + defaultValue: false, + help: "Whether to enable the namespace generator plugin.", + }) + app.options.addDeclaration({ + name: "generateNamespaces", + type: ParameterType.Mixed, + defaultValue: [], + help: "The namespaces to generate.", + }) -export class GenerateNamespacePlugin { - private options?: PluginOptions - private app: Application - private parentNamespace?: DeclarationReflection - private currentNamespaceHeirarchy: DeclarationReflection[] - private currentContext?: Context - private scannedComments = false + const generatedNamespaces: Map = new Map() - constructor(app: Application) { - this.app = app - this.currentNamespaceHeirarchy = [] - this.declareOptions() - - this.app.converter.on( - Converter.EVENT_RESOLVE, - this.handleCreateDeclarationEvent.bind(this) - ) - this.app.converter.on( - Converter.EVENT_CREATE_DECLARATION, - this.scanComments.bind(this) - ) - } - - declareOptions() { - this.app.options.addDeclaration({ - name: "generateNamespaces", - type: ParameterType.Boolean, - defaultValue: false, - help: "Whether to enable conversion of categories to namespaces.", - }) - this.app.options.addDeclaration({ - name: "parentNamespace", - type: ParameterType.String, - defaultValue: "", - help: "Optionally specify a parent namespace to place all generated namespaces in.", - }) - this.app.options.addDeclaration({ - name: "namePrefix", - type: ParameterType.String, - defaultValue: "", - help: "Optionally specify a name prefix for all namespaces.", - }) - } - - readOptions() { - if (this.options) { + app.converter.on(Converter.EVENT_BEGIN, (context) => { + if (!app.options.getValue("enableNamespaceGenerator")) { return } - this.options = { - generateNamespaces: this.app.options.getValue("generateNamespaces"), - parentNamespace: this.app.options.getValue("parentNamespace"), - namePrefix: this.app.options.getValue("namePrefix"), - } - } + const namespaces = app.options.getValue( + "generateNamespaces" + ) as unknown as NamespaceGenerateDetails[] - loadNamespace(namespaceName: string): DeclarationReflection { - const formattedName = this.formatName(namespaceName) - return this.currentContext?.project - .getReflectionsByKind(ReflectionKind.Namespace) - .find( - (m) => - m.name === formattedName && - (!this.currentNamespaceHeirarchy.length || - m.parent?.id === - this.currentNamespaceHeirarchy[ - this.currentNamespaceHeirarchy.length - 1 - ].id) - ) as DeclarationReflection - } + namespaces.forEach((namespace) => { + const genNamespace = context.createDeclarationReflection( + ReflectionKind.Namespace, + void 0, + void 0, + namespace.name + ) - createNamespace(namespaceName: string): DeclarationReflection | undefined { - if (!this.currentContext) { - return - } - const formattedName = this.formatName(namespaceName) - const namespace = this.currentContext?.createDeclarationReflection( - ReflectionKind.Namespace, - void 0, - void 0, - formattedName - ) - - namespace.children = [] - - return namespace - } - - formatName(namespaceName: string): string { - return `${this.options?.namePrefix}${namespaceName}` - } - - generateNamespaceFromTag({ - tag, - summary, - }: { - tag: CommentTag - reflection?: DeclarationReflection - summary?: CommentDisplayPart[] - }) { - const categoryHeirarchy = tag.content[0].text.split(".") - categoryHeirarchy.forEach((cat, index) => { - // check whether a namespace exists with the category name. - let namespace = this.loadNamespace(cat) - - if (!namespace) { - // add a namespace for this category - namespace = this.createNamespace(cat) || namespace - - namespace.comment = new Comment() - if (this.currentNamespaceHeirarchy.length) { - namespace.comment.modifierTags.add("@namespaceMember") - } - if (summary && index === categoryHeirarchy.length - 1) { - namespace.comment.summary = summary - } + if (namespace.description) { + genNamespace.comment = new Comment([ + { + kind: "text", + text: namespace.description, + }, + ]) } - this.currentContext = - this.currentContext?.withScope(namespace) || this.currentContext - this.currentNamespaceHeirarchy.push(namespace) + generatedNamespaces.set(namespace.pathPattern, genNamespace) }) - } + }) - /** - * create categories in the last namespace if the - * reflection has a category - */ - attachCategories( - reflection: DeclarationReflection, - comments: Comment | undefined - ) { - if (!this.currentNamespaceHeirarchy.length) { - return - } - - const parentNamespace = - this.currentNamespaceHeirarchy[this.currentNamespaceHeirarchy.length - 1] - comments?.blockTags - .filter((tag) => tag.tag === "@category") - .forEach((tag) => { - const categoryName = tag.content[0].text - if (!parentNamespace.categories) { - parentNamespace.categories = [] - } - let category = parentNamespace.categories.find( - (category) => category.title === categoryName - ) - if (!category) { - category = new ReflectionCategory(categoryName) - parentNamespace.categories.push(category) - } - category.children.push(reflection) - }) - } - - handleCreateDeclarationEvent(context: Context, reflection: Reflection) { - if (!(reflection instanceof DeclarationReflection)) { - return - } - this.readOptions() - if (this.options?.parentNamespace && !this.parentNamespace) { - this.parentNamespace = - this.loadNamespace(this.options.parentNamespace) || - this.createNamespace(this.options.parentNamespace) - } - this.currentNamespaceHeirarchy = [] - if (this.parentNamespace) { - this.currentNamespaceHeirarchy.push(this.parentNamespace) - } - this.currentContext = context - const comments = this.getReflectionComments(reflection) - comments?.blockTags - .filter((tag) => tag.tag === "@customNamespace") - .forEach((tag) => { - this.generateNamespaceFromTag({ - tag, - }) - if ( - reflection.parent instanceof DeclarationReflection || - reflection.parent?.isProject() - ) { - reflection.parent.children = reflection.parent.children?.filter( - (child) => child.id !== reflection.id - ) - } - this.currentContext?.addChild(reflection) - }) - - comments?.removeTags("@customNamespace") - this.attachCategories(reflection, comments) - this.currentContext = undefined - this.currentNamespaceHeirarchy = [] - } - - /** - * Scan all source files for `@customNamespace` tag to generate namespaces - * This is mainly helpful to pull summaries of the namespaces. - */ - scanComments(context: Context) { - if (this.scannedComments) { - return - } - this.currentContext = context - const fileNames = context.program.getRootFileNames() - - fileNames.forEach((fileName) => { - const sourceFile = context.program.getSourceFile(fileName) - if (!sourceFile) { + app.converter.on( + Converter.EVENT_CREATE_DECLARATION, + (context, reflection) => { + if (!app.options.getValue("enableNamespaceGenerator")) { return } - const comments = context.getFileComment(sourceFile) - comments?.blockTags - .filter((tag) => tag.tag === "@customNamespace") - .forEach((tag) => { - this.generateNamespaceFromTag({ tag, summary: comments.summary }) - if (this.currentNamespaceHeirarchy.length) { - // add comments of the file to the last created namespace - this.currentNamespaceHeirarchy[ - this.currentNamespaceHeirarchy.length - 1 - ].comment = comments + const symbol = context.project.getSymbolFromReflection(reflection) + const filePath = symbol?.valueDeclaration?.getSourceFile().fileName - this.currentNamespaceHeirarchy[ - this.currentNamespaceHeirarchy.length - 1 - ].comment!.blockTags = this.currentNamespaceHeirarchy[ - this.currentNamespaceHeirarchy.length - 1 - ].comment!.blockTags.filter((tag) => tag.tag !== "@customNamespace") - } - // reset values - this.currentNamespaceHeirarchy = [] - this.currentContext = context - }) - }) + if (!filePath) { + return + } - this.scannedComments = true - } + generatedNamespaces.forEach((namespace, pathPattern) => { + if (!minimatch(filePath, pathPattern)) { + return + } - getReflectionComments( - reflection: DeclarationReflection - ): Comment | undefined { - if (reflection.comment) { - return reflection.comment + namespace.addChild(reflection) + }) } - - // try to retrieve comment from signature - if (!reflection.signatures?.length) { - return - } - return reflection.signatures.find((signature) => signature.comment)?.comment - } - - // for debugging - printCurrentHeirarchy() { - return this.currentNamespaceHeirarchy.map((heirarchy) => heirarchy.name) - } + ) } diff --git a/www/utils/packages/typedoc-plugin-custom/src/index.ts b/www/utils/packages/typedoc-plugin-custom/src/index.ts index 5adf125339..54720d5aa4 100644 --- a/www/utils/packages/typedoc-plugin-custom/src/index.ts +++ b/www/utils/packages/typedoc-plugin-custom/src/index.ts @@ -7,7 +7,7 @@ import { load as eslintExamplePlugin } from "./eslint-example" import { load as signatureModifierPlugin } from "./signature-modifier" import { MermaidDiagramGenerator } from "./mermaid-diagram-generator" import { load as parentIgnorePlugin } from "./parent-ignore" -import { GenerateNamespacePlugin } from "./generate-namespace" +import { load as generateNamespacePlugin } from "./generate-namespace" import { DmlRelationsResolver } from "./dml-relations-resolver" import { load as dmlTypesNormalizer } from "./dml-types-normalizer" import { MermaidDiagramDMLGenerator } from "./mermaid-diagram-dml-generator" @@ -23,8 +23,8 @@ export function load(app: Application) { parentIgnorePlugin(app) dmlTypesNormalizer(app) dmlJsonParser(app) + generateNamespacePlugin(app) - new GenerateNamespacePlugin(app) new MermaidDiagramGenerator(app) new DmlRelationsResolver(app) new MermaidDiagramDMLGenerator(app) diff --git a/www/utils/packages/types/lib/index.d.ts b/www/utils/packages/types/lib/index.d.ts index c8adc4f905..42db2c0639 100644 --- a/www/utils/packages/types/lib/index.d.ts +++ b/www/utils/packages/types/lib/index.d.ts @@ -197,19 +197,6 @@ export declare module "typedoc" { * @defaultValue true */ outputModules: boolean - /** - * Whether to enable category to namespace conversion. - * @defaultValue false - */ - generateNamespaces: boolean - /** - * Optionally specify a parent namespace to place all generated namespaces in. - */ - parentNamespace: string - /** - * Optionally specify a name prefix for all generated namespaces. - */ - namePrefix: string /** * Whether to enable the React Query manipulator. * @defaultValue false @@ -262,6 +249,15 @@ export declare module "typedoc" { * @defaultValue false */ enableWorkflowsPlugins: boolean + /** + * Whether to enable the namespace generator plugin. + * @defaultValue false + */ + enableNamespaceGenerator: boolean + /** + * The namespaces to generate. + */ + generateNamespaces: NamespaceGenerateDetails[] } } @@ -273,3 +269,21 @@ export declare type DmlFile = { properties: DmlObject } } + +export declare type NamespaceGenerateDetails = { + /** + * The namespace's names. + */ + name: string + /** + * The namespace's description. Will be attached + * as a summary comment. + */ + description?: string + /** + * A path pattern to pass to minimatch that + * checks if a file / its reflections belong to the + * namespace + */ + pathPattern: string +} diff --git a/www/utils/packages/utils/src/workflow-utils.ts b/www/utils/packages/utils/src/workflow-utils.ts index 15eac08565..a5182f5701 100644 --- a/www/utils/packages/utils/src/workflow-utils.ts +++ b/www/utils/packages/utils/src/workflow-utils.ts @@ -2,7 +2,7 @@ import { SignatureReflection } from "typedoc" export function isWorkflow(reflection: SignatureReflection): boolean { return ( - reflection.parent.children?.some((child) => child.name === "runAsStep") || + reflection.parent?.children?.some((child) => child.name === "runAsStep") || false ) } diff --git a/www/utils/yarn.lock b/www/utils/yarn.lock index 1fdd6c705f..5267cac613 100644 --- a/www/utils/yarn.lock +++ b/www/utils/yarn.lock @@ -3906,6 +3906,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.0.1": + version: 10.0.1 + resolution: "minimatch@npm:10.0.1" + dependencies: + brace-expansion: ^2.0.1 + checksum: e6c29a81fe83e1877ad51348306be2e8aeca18c88fdee7a99df44322314279e15799e41d7cb274e4e8bb0b451a3bc622d6182e157dfa1717d6cda75e9cd8cd5d + languageName: node + linkType: hard + "minimatch@npm:^3.0.2, minimatch@npm:^3.0.3, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -5374,6 +5383,7 @@ __metadata: "@types/node": ^16.11.10 eslint: ^8.53.0 glob: ^10.3.10 + minimatch: ^10.0.1 types: "*" typescript: 5.5 utils: "*"