From 9a5ca86b763346b10df4716ef83bf2ed7301f9b9 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 13 Oct 2025 13:31:48 +0300 Subject: [PATCH] docs: support since, deprecated, and feature flag tags in dml reference (#13741) --- .../Notices/DeprecatedNotice/index.tsx | 32 ++++++++ .../{ => Notices}/ExpandableNotice/index.tsx | 0 .../{ => Notices}/FeatureFlagNotice/index.tsx | 0 .../Notices/VersionNotice/index.tsx | 37 +++++++++ .../src/components/TypeList/Items/index.tsx | 11 +++ .../docs-ui/src/components/TypeList/index.tsx | 5 ++ www/packages/docs-ui/src/components/index.ts | 6 +- .../src/classes/kinds/default.ts | 21 +++++ .../docs-generator/src/classes/kinds/dml.ts | 35 ++++++++ .../src/dml-json-parser.ts | 82 ++++++++++++++++++- .../src/resources/helpers/version.ts | 2 +- .../src/resources/partials/member.dml.hbs | 2 + .../src/types.ts | 5 ++ .../src/utils/reflection-formatter.ts | 15 ++++ .../src/utils/reflection-type-parameters.ts | 20 ++++- www/utils/packages/types/lib/index.d.ts | 6 ++ 16 files changed, 274 insertions(+), 5 deletions(-) create mode 100644 www/packages/docs-ui/src/components/Notices/DeprecatedNotice/index.tsx rename www/packages/docs-ui/src/components/{ => Notices}/ExpandableNotice/index.tsx (100%) rename www/packages/docs-ui/src/components/{ => Notices}/FeatureFlagNotice/index.tsx (100%) create mode 100644 www/packages/docs-ui/src/components/Notices/VersionNotice/index.tsx diff --git a/www/packages/docs-ui/src/components/Notices/DeprecatedNotice/index.tsx b/www/packages/docs-ui/src/components/Notices/DeprecatedNotice/index.tsx new file mode 100644 index 0000000000..345db7d72e --- /dev/null +++ b/www/packages/docs-ui/src/components/Notices/DeprecatedNotice/index.tsx @@ -0,0 +1,32 @@ +import React from "react" +import { Badge, Tooltip } from "@/components" + +export type DeprecatedNoticeProps = { + description?: string + tooltipTextClassName?: string + badgeClassName?: string + badgeContent?: React.ReactNode +} + +export const DeprecatedNotice = ({ + description, + tooltipTextClassName, + badgeClassName, + badgeContent = `Deprecated`, +}: DeprecatedNoticeProps) => { + return ( + + {description || + "This feature is deprecated and may be removed in future releases."} + + } + clickable + > + + {badgeContent} + + + ) +} diff --git a/www/packages/docs-ui/src/components/ExpandableNotice/index.tsx b/www/packages/docs-ui/src/components/Notices/ExpandableNotice/index.tsx similarity index 100% rename from www/packages/docs-ui/src/components/ExpandableNotice/index.tsx rename to www/packages/docs-ui/src/components/Notices/ExpandableNotice/index.tsx diff --git a/www/packages/docs-ui/src/components/FeatureFlagNotice/index.tsx b/www/packages/docs-ui/src/components/Notices/FeatureFlagNotice/index.tsx similarity index 100% rename from www/packages/docs-ui/src/components/FeatureFlagNotice/index.tsx rename to www/packages/docs-ui/src/components/Notices/FeatureFlagNotice/index.tsx diff --git a/www/packages/docs-ui/src/components/Notices/VersionNotice/index.tsx b/www/packages/docs-ui/src/components/Notices/VersionNotice/index.tsx new file mode 100644 index 0000000000..5fd5e24272 --- /dev/null +++ b/www/packages/docs-ui/src/components/Notices/VersionNotice/index.tsx @@ -0,0 +1,37 @@ +import React from "react" +import { Badge, Tooltip } from "@/components" + +export type VersionNoticeProps = { + version: string + tooltipTextClassName?: string + badgeClassName?: string + badgeContent?: React.ReactNode +} + +export const VersionNotice = ({ + version, + tooltipTextClassName, + badgeClassName, + badgeContent = `v${version}`, +}: VersionNoticeProps) => { + return ( + + This is available starting from +
+ + Medusa v{version} + + + } + clickable + > + + {badgeContent} + +
+ ) +} diff --git a/www/packages/docs-ui/src/components/TypeList/Items/index.tsx b/www/packages/docs-ui/src/components/TypeList/Items/index.tsx index 9a072c2e50..515542ef28 100644 --- a/www/packages/docs-ui/src/components/TypeList/Items/index.tsx +++ b/www/packages/docs-ui/src/components/TypeList/Items/index.tsx @@ -22,6 +22,8 @@ import { import { decodeStr, isInView } from "@/utils" import { usePathname } from "next/navigation" import { useIsBrowser, useSiteConfig } from "../../.." +import { VersionNotice } from "../../Notices/VersionNotice" +import { DeprecatedNotice } from "../../Notices/DeprecatedNotice" type CommonProps = ParentCommonProps & { level?: number @@ -236,6 +238,15 @@ const TypeListItem = ({ badgeContent={} /> )} + {item.since && ( + + )} + {item.deprecated?.is_deprecated && ( + + )} diff --git a/www/packages/docs-ui/src/components/TypeList/index.tsx b/www/packages/docs-ui/src/components/TypeList/index.tsx index 406d5444ce..1963150707 100644 --- a/www/packages/docs-ui/src/components/TypeList/index.tsx +++ b/www/packages/docs-ui/src/components/TypeList/index.tsx @@ -17,6 +17,11 @@ export type Type = { featureFlag?: string expandable: boolean children?: Type[] + deprecated?: { + is_deprecated: boolean + description?: string + } + since?: string } type ParameterTypesType = { diff --git a/www/packages/docs-ui/src/components/index.ts b/www/packages/docs-ui/src/components/index.ts index 622eba4f20..cfe06c6705 100644 --- a/www/packages/docs-ui/src/components/index.ts +++ b/www/packages/docs-ui/src/components/index.ts @@ -22,8 +22,10 @@ export * from "./Details/Summary" export * from "./DetailsList" export * from "./DottedSeparator" export * from "./EditButton" -export * from "./ExpandableNotice" -export * from "./FeatureFlagNotice" +export * from "./Notices/ExpandableNotice" +export * from "./Notices/FeatureFlagNotice" +export * from "./Notices/DeprecatedNotice" +export * from "./Notices/VersionNotice" export * from "./Feedback" export * from "./Feedback/Solutions" export * from "./Footer" diff --git a/www/utils/packages/docs-generator/src/classes/kinds/default.ts b/www/utils/packages/docs-generator/src/classes/kinds/default.ts index 6e7d349351..d4e03f1633 100644 --- a/www/utils/packages/docs-generator/src/classes/kinds/default.ts +++ b/www/utils/packages/docs-generator/src/classes/kinds/default.ts @@ -606,14 +606,22 @@ class DefaultKindGenerator { deprecatedTag: ts.JSDocTag | undefined sinceTag: ts.JSDocTag | undefined featureFlagTag: ts.JSDocTag | undefined + summary: string | undefined } { const nodeComments = ts.getJSDocCommentsAndTags(node) let deprecatedTag: ts.JSDocTag | undefined let sinceTag: ts.JSDocTag | undefined let featureFlagTag: ts.JSDocTag | undefined + let summary: string | undefined nodeComments.forEach((comment) => { if (!("tags" in comment)) { + if (ts.isJSDoc(comment) && comment.comment) { + summary = + typeof comment.comment === "string" + ? comment.comment + : comment.comment.map((part) => part.text).join(" ") + } return } @@ -636,9 +644,22 @@ class DefaultKindGenerator { deprecatedTag, sinceTag, featureFlagTag, + summary, } } + formatJSDocTag(tag: ts.JSDocTag | undefined): string | undefined { + if (!tag) { + return undefined + } + + if (typeof tag.comment === "string") { + return tag.comment + } + + return tag.comment?.map((part) => part.text).join(" ") + } + /** * Check if a node is ignored. * diff --git a/www/utils/packages/docs-generator/src/classes/kinds/dml.ts b/www/utils/packages/docs-generator/src/classes/kinds/dml.ts index 471940392c..f867c07d9a 100644 --- a/www/utils/packages/docs-generator/src/classes/kinds/dml.ts +++ b/www/utils/packages/docs-generator/src/classes/kinds/dml.ts @@ -101,10 +101,24 @@ class DmlKindGenerator extends DefaultKindGenerator { dataModelName, }) + /** + * Use parent to get tags like since, deprecated, featureFlag + */ + const parent = node.parent?.parent?.parent + + const { sinceTag, deprecatedTag, featureFlagTag } = + this.getInformationFromTags(parent) + const dmlFile: DmlFile = { [dataModelName]: { filePath: getBasePath(node.getSourceFile().fileName), properties, + since: this.formatJSDocTag(sinceTag), + deprecated: { + is_deprecated: !!deprecatedTag, + description: this.formatJSDocTag(deprecatedTag), + }, + featureFlag: this.formatJSDocTag(featureFlagTag), }, } @@ -229,8 +243,11 @@ class DmlKindGenerator extends DefaultKindGenerator { ) const isBoolean = propertyTypeStr.includes("BooleanProperty") const relationName = isRelation ? camelToWords(propertyName) : undefined + const { summary, sinceTag, deprecatedTag, featureFlagTag } = + this.getInformationFromTags(propertyNode) let propertyDescription = + summary || this.knowledgeBaseFactory.tryToGetObjectPropertySummary({ retrieveOptions: { str: propertyName, @@ -251,6 +268,24 @@ class DmlKindGenerator extends DefaultKindGenerator { propertyDescription += `\n\n@expandable` } + if (sinceTag) { + propertyDescription += `\n\n@since ${ + this.formatJSDocTag(sinceTag) ?? "" + }` + } + + if (featureFlagTag) { + propertyDescription += `\n\n@featureFlag ${ + this.formatJSDocTag(featureFlagTag) ?? "" + }` + } + + if (deprecatedTag) { + propertyDescription += `\n\n@deprecated ${ + this.formatJSDocTag(deprecatedTag) ?? "" + }` + } + properties[propertyName] = propertyDescription }) diff --git a/www/utils/packages/typedoc-plugin-custom/src/dml-json-parser.ts b/www/utils/packages/typedoc-plugin-custom/src/dml-json-parser.ts index 5cbbeab277..8225344ab4 100644 --- a/www/utils/packages/typedoc-plugin-custom/src/dml-json-parser.ts +++ b/www/utils/packages/typedoc-plugin-custom/src/dml-json-parser.ts @@ -3,6 +3,7 @@ import path from "path" import { Application, Comment, + CommentTag, Context, Converter, DeclarationReflection, @@ -12,6 +13,9 @@ import { getDirname, getDmlProperties, isDmlEntity } from "utils" import { DmlFile } from "types" const FILE_NAME_REGEX = /packages\/modules\/(?[a-z-]+)/ +const SINCE_REGEX = /@since\s+([\d.]+)/ +const DEPRECATED_REGEX = /@deprecated\s+(.+)/ +const FEATURE_FLAG_REGEX = /@featureFlag\s+(\S+)/ export function load(app: Application) { app.converter.on( @@ -76,6 +80,41 @@ function getDescriptionsFromJson( if (!jsonFileContent[reflection.name]) { return } + const comment = reflection.comment || new Comment() + + if (jsonFileContent[reflection.name].since) { + comment.blockTags.push( + new CommentTag("@since", [ + { + kind: "text", + text: jsonFileContent[reflection.name].since!, + }, + ]) + ) + } + + if (jsonFileContent[reflection.name].deprecated?.is_deprecated) { + comment.blockTags.push( + new CommentTag("@deprecated", [ + { + kind: "text", + text: jsonFileContent[reflection.name].deprecated!.description || "", + }, + ]) + ) + } + + if (jsonFileContent[reflection.name].featureFlag) { + comment.blockTags.push( + new CommentTag("@featureFlag", [ + { + kind: "text", + text: jsonFileContent[reflection.name].featureFlag!, + }, + ]) + ) + } + reflection.comment = comment Object.entries(jsonFileContent[reflection.name].properties).forEach( ([propertyName, description]) => { @@ -90,16 +129,57 @@ function getDescriptionsFromJson( const comment = propertyReflection.comment || new Comment() const isExpandable = description.includes("@expandable") + const sinceMatch = description.match(SINCE_REGEX) + const featureFlagMatch = description.match(FEATURE_FLAG_REGEX) + const deprecatedMatch = description.match(DEPRECATED_REGEX) comment.summary.push({ kind: "text", - text: description.replace("@expandable", "").trim(), + text: description + .replace("@expandable", "") + .replace(SINCE_REGEX, "") + .replace(FEATURE_FLAG_REGEX, "") + .replace(DEPRECATED_REGEX, "") + .trim(), }) if (isExpandable) { comment.modifierTags.add("@expandable") } + if (sinceMatch) { + comment.blockTags.push( + new CommentTag("@since", [ + { + kind: "text", + text: sinceMatch[1], + }, + ]) + ) + } + + if (featureFlagMatch) { + comment.blockTags.push( + new CommentTag("@featureFlag", [ + { + kind: "text", + text: featureFlagMatch[1], + }, + ]) + ) + } + + if (deprecatedMatch) { + comment.blockTags.push( + new CommentTag("@deprecated", [ + { + kind: "text", + text: deprecatedMatch[1], + }, + ]) + ) + } + propertyReflection.comment = comment } ) diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/version.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/version.ts index b98e9ef798..41a58a948d 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/version.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/version.ts @@ -13,6 +13,6 @@ export default function () { const tagContent = sinceTag.content.map((content) => content.text).join("") - return `:::note\n\nThis is available starting from Medusa \`v${tagContent}\`.\n\n:::` + return `:::note\n\nThis is available starting from [Medusa v${tagContent}](https://github.com/medusajs/medusa/releases/tag/v${tagContent}).\n\n:::` }) } diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/partials/member.dml.hbs b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/partials/member.dml.hbs index ef889a6e12..f4f0964a2b 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/partials/member.dml.hbs +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/partials/member.dml.hbs @@ -4,6 +4,8 @@ {{/if}} +{{{version this}}} + {{{sourceCodeLink}}} {{{dmlProperties}}} \ No newline at end of file diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/types.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/types.ts index db3e027806..888ab349f7 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/types.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/types.ts @@ -34,4 +34,9 @@ export type Parameter = { featureFlag?: string expandable: boolean children?: Parameter[] + since?: string + deprecated?: { + is_deprecated: boolean + description?: string + } } diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts index 1e279bc4e2..edfaeb1399 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts @@ -133,6 +133,10 @@ export function reflectionComponentFormatter({ reflection.flags.isOptional || reflection.kind === ReflectionKind.EnumMember const comments = getComments(reflection) + const deprecatedTag = comments?.blockTags.find( + (tag) => tag.tag === "@deprecated" + ) + const sinceTag = comments?.blockTags.find((tag) => tag.tag === "@since") const componentItem: Parameter = { name: reflection.name, type: reflection.type @@ -160,6 +164,17 @@ export function reflectionComponentFormatter({ children: [], } + if (sinceTag) { + componentItem.since = sinceTag.content.map((c) => c.text).join("") + } + + if (deprecatedTag) { + componentItem.deprecated = { + is_deprecated: true, + description: deprecatedTag?.content.map((c) => c.text).join(""), + } + } + if (level + 1 > (maxLevel || MarkdownTheme.MAX_LEVEL)) { return componentItem } diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-type-parameters.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-type-parameters.ts index bb84c45ea1..50c46b2d96 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-type-parameters.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-type-parameters.ts @@ -66,7 +66,12 @@ export function getReflectionTypeParameters({ description = loadComment(typeName, project) } - return { + const deprecatedTag = comment?.blockTags.find( + (tag) => tag.tag === "@deprecated" + ) + const sinceTag = comment?.blockTags.find((tag) => tag.tag === "@since") + + const parameter: Parameter = { name: "name" in reflectionType ? reflectionType.name : typeName, type, optional: @@ -84,6 +89,19 @@ export function getReflectionTypeParameters({ featureFlag: Handlebars.helpers.featureFlag(comment), children: [], } + + if (sinceTag) { + parameter.since = sinceTag.content.map((c) => c.text).join("") + } + + if (deprecatedTag) { + parameter.deprecated = { + is_deprecated: true, + description: deprecatedTag?.content.map((c) => c.text).join(""), + } + } + + return parameter } const componentItem: Parameter[] = [] diff --git a/www/utils/packages/types/lib/index.d.ts b/www/utils/packages/types/lib/index.d.ts index 09519d2728..3d766231aa 100644 --- a/www/utils/packages/types/lib/index.d.ts +++ b/www/utils/packages/types/lib/index.d.ts @@ -307,6 +307,12 @@ export declare type DmlFile = { [k: string]: { filePath: string properties: DmlObject + since?: string + deprecated?: { + is_deprecated: boolean + description?: string + } + featureFlag?: string } }