From 697556fd16191b42c45a9b62f1eef0176e29827b Mon Sep 17 00:00:00 2001
From: Qjuh <76154676+Qjuh@users.noreply.github.com>
Date: Wed, 22 Oct 2025 13:53:56 +0200
Subject: [PATCH] feat(website): parse and show unstable tsdoc tag (#11187)
feat(website): parse and show unstable tsDoc tag
---
apps/website/src/components/Badges.tsx | 11 +++++++++--
apps/website/src/components/DocItem.tsx | 5 +++++
apps/website/src/components/EnumMemberNode.tsx | 5 +++++
apps/website/src/components/EventNode.tsx | 5 +++++
apps/website/src/components/MethodNode.tsx | 5 +++++
apps/website/src/components/PropertyNode.tsx | 5 +++++
apps/website/src/components/UnstableNode.tsx | 18 ++++++++++++++++++
.../scripts/src/generateSplitDocumentation.ts | 7 +++++++
8 files changed, 59 insertions(+), 2 deletions(-)
create mode 100644 apps/website/src/components/UnstableNode.tsx
diff --git a/apps/website/src/components/Badges.tsx b/apps/website/src/components/Badges.tsx
index d1bf0c336..14afcf6b7 100644
--- a/apps/website/src/components/Badges.tsx
+++ b/apps/website/src/components/Badges.tsx
@@ -13,6 +13,7 @@ export function Badge({ children, className = '' }: PropsWithChildren<{ readonly
export async function Badges({ node }: { readonly node: any }) {
const isDeprecated = Boolean(node.summary?.deprecatedBlock?.length);
+ const isUnstable = Boolean(node.summary?.unstableBlock?.length);
const isProtected = node.isProtected;
const isStatic = node.isStatic;
const isAbstract = node.isAbstract;
@@ -20,8 +21,9 @@ export async function Badges({ node }: { readonly node: any }) {
const isOptional = node.isOptional;
const isExternal = node.isExternal;
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- const isAny = isDeprecated || isProtected || isStatic || isAbstract || isReadonly || isOptional || isExternal;
+ const isAny =
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+ isDeprecated || isUnstable || isProtected || isStatic || isAbstract || isReadonly || isOptional || isExternal;
return isAny ? (
@@ -30,6 +32,11 @@ export async function Badges({ node }: { readonly node: any }) {
deprecated
) : null}
+ {isUnstable ? (
+
+ unstable
+
+ ) : null}
{isProtected ?
protected : null}
{isStatic ?
static : null}
{isAbstract ?
abstract : null}
diff --git a/apps/website/src/components/DocItem.tsx b/apps/website/src/components/DocItem.tsx
index 6defe885b..c4339d620 100644
--- a/apps/website/src/components/DocItem.tsx
+++ b/apps/website/src/components/DocItem.tsx
@@ -15,6 +15,7 @@ import { SummaryNode } from './SummaryNode';
import { SyntaxHighlighter } from './SyntaxHighlighter';
import { TypeParameterNode } from './TypeParameterNode';
import { UnionMember } from './UnionMember';
+import { UnstableNode } from './UnstableNode';
import { Tab, TabList, TabPanel, Tabs } from './ui/Tabs';
async function OverloadNode({
@@ -81,6 +82,10 @@ export async function DocItem({
) : null}
+ {node.summary?.unstableBlock.length ? (
+
+ ) : null}
+
{node.summary?.summarySection ?
: null}
{node.summary?.returnsBlock.length ?
: null}
diff --git a/apps/website/src/components/EnumMemberNode.tsx b/apps/website/src/components/EnumMemberNode.tsx
index daba76b3f..49a0efb50 100644
--- a/apps/website/src/components/EnumMemberNode.tsx
+++ b/apps/website/src/components/EnumMemberNode.tsx
@@ -12,6 +12,7 @@ import { ParameterNode } from './ParameterNode';
import { ReturnNode } from './ReturnNode';
import { SeeNode } from './SeeNode';
import { SummaryNode } from './SummaryNode';
+import { UnstableNode } from './UnstableNode';
export async function EnumMemberNode({
node,
@@ -80,6 +81,10 @@ export async function EnumMemberNode({
) : null}
+ {enumMember.summary?.unstableBlock.length ? (
+
+ ) : null}
+
{enumMember.summary?.summarySection.length ? (
) : null}
diff --git a/apps/website/src/components/EventNode.tsx b/apps/website/src/components/EventNode.tsx
index f515de502..1d55646ce 100644
--- a/apps/website/src/components/EventNode.tsx
+++ b/apps/website/src/components/EventNode.tsx
@@ -11,6 +11,7 @@ import { ReturnNode } from './ReturnNode';
import { SeeNode } from './SeeNode';
import { SummaryNode } from './SummaryNode';
import { TypeParameterNode } from './TypeParameterNode';
+import { UnstableNode } from './UnstableNode';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';
import { Tab, TabList, TabPanel, Tabs } from './ui/Tabs';
@@ -68,6 +69,10 @@ async function EventBodyNode({
) : null}
+ {event.summary?.unstableBlock.length ? (
+
+ ) : null}
+
{event.summary?.summarySection.length ? (
) : null}
diff --git a/apps/website/src/components/MethodNode.tsx b/apps/website/src/components/MethodNode.tsx
index 9ed68d3b5..7db496c9f 100644
--- a/apps/website/src/components/MethodNode.tsx
+++ b/apps/website/src/components/MethodNode.tsx
@@ -12,6 +12,7 @@ import { ReturnNode } from './ReturnNode';
import { SeeNode } from './SeeNode';
import { SummaryNode } from './SummaryNode';
import { TypeParameterNode } from './TypeParameterNode';
+import { UnstableNode } from './UnstableNode';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';
import { Tab, TabList, TabPanel, Tabs } from './ui/Tabs';
@@ -70,6 +71,10 @@ async function MethodBodyNode({
) : null}
+ {method.summary?.unstableBlock.length ? (
+
+ ) : null}
+
{method.summary?.summarySection.length ? (
) : null}
diff --git a/apps/website/src/components/PropertyNode.tsx b/apps/website/src/components/PropertyNode.tsx
index 02ce22b0b..ebdd24f30 100644
--- a/apps/website/src/components/PropertyNode.tsx
+++ b/apps/website/src/components/PropertyNode.tsx
@@ -9,6 +9,7 @@ import { ExcerptNode } from './ExcerptNode';
import { InheritedFromNode } from './InheritedFromNode';
import { SeeNode } from './SeeNode';
import { SummaryNode } from './SummaryNode';
+import { UnstableNode } from './UnstableNode';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';
export async function PropertyNode({
@@ -79,6 +80,10 @@ export async function PropertyNode({
) : null}
+ {property.summary?.unstableBlock.length ? (
+
+ ) : null}
+
{property.summary?.summarySection.length ? (
) : null}
diff --git a/apps/website/src/components/UnstableNode.tsx b/apps/website/src/components/UnstableNode.tsx
new file mode 100644
index 000000000..26455c3ee
--- /dev/null
+++ b/apps/website/src/components/UnstableNode.tsx
@@ -0,0 +1,18 @@
+import { DocNode } from './DocNode';
+import { Alert } from './ui/Alert';
+
+export async function UnstableNode({
+ unstableBlock,
+ version,
+}: {
+ readonly unstableBlock: any;
+ readonly version: string;
+}) {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/packages/scripts/src/generateSplitDocumentation.ts b/packages/scripts/src/generateSplitDocumentation.ts
index ffdf1e65c..87f164f33 100644
--- a/packages/scripts/src/generateSplitDocumentation.ts
+++ b/packages/scripts/src/generateSplitDocumentation.ts
@@ -413,6 +413,8 @@ function itemTsDoc(item: DocNode, apiItem: ApiItem) {
(block) => block.blockTag.tagNameWithUpperCase === StandardTags.defaultValue.tagNameWithUpperCase,
);
+ const unstableBlock = comment.customBlocks.find((block) => block.blockTag.tagNameWithUpperCase === '@UNSTABLE');
+
const mixesBlocks = comment.customBlocks.filter((block) => block.blockTag.tagNameWithUpperCase === '@MIXES');
return {
@@ -442,6 +444,11 @@ function itemTsDoc(item: DocNode, apiItem: ApiItem) {
.flat(1)
.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)
: [],
+ unstableBlock: unstableBlock
+ ? createNode(unstableBlock.content)
+ .flat(1)
+ .filter((val: any) => val.kind !== DocNodeKind.SoftBreak)
+ : [],
exampleBlocks: exampleBlocks
.flatMap((block) => createNode(block.content).flat(1))
.filter((val: any) => val.kind !== DocNodeKind.SoftBreak),