Skip to content

Commit 22b549e

Browse files
authored
build(docs): Update @fluid-tools/api-markdown-documenter (#25889)
Updates API docs infra to accommodate API changes in the library. Most notably: custom transformation logic now targets [mdast](https://github.com/syntax-tree/mdast) directly, rather than the bespoke documentation tree representation that has been removed from the library. Also picks up some misc. fixes for API docs generation that have been made in the documenter library.
1 parent 7e80360 commit 22b549e

File tree

7 files changed

+176
-349
lines changed

7 files changed

+176
-349
lines changed

docs/infra/api-markdown-documenter/admonition-node.mjs

Lines changed: 0 additions & 106 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*!
2+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
//@ts-check
7+
/** @typedef {import("mdast").BlockContent} BlockContent */
8+
/** @typedef {import("mdast-util-directive").ContainerDirective} ContainerDirective */
9+
/** @typedef {import("mdast").PhrasingContent} PhrasingContent */
10+
/** @typedef {"note" | "tip" | "info" | "warning" | "danger"} AdmonitionKind */
11+
12+
/**
13+
* Generates Markdown representing a Docusaurus Admonition.
14+
*
15+
* @param {BlockContent[]} body - Admonition body content.
16+
* @param {AdmonitionKind} admonitionKind - The kind of admonition. See {@link https://docusaurus.io/docs/markdown-features/admonitions}.
17+
* @param {string | undefined} title - (Optional) Title text for the admonition.
18+
*
19+
* @returns {ContainerDirective} The Markdown AST representing the admonition.
20+
*/
21+
export function createAdmonition(body, admonitionKind, title) {
22+
/** @type {BlockContent[]} */
23+
const children = [];
24+
25+
// If the admonition has a title, prepend it to the list of children with the `directiveLabel` property set.
26+
if (title !== undefined) {
27+
children.push({
28+
type: "paragraph",
29+
data: {
30+
directiveLabel: true,
31+
},
32+
children: [
33+
{
34+
type: "text",
35+
value: title,
36+
},
37+
],
38+
});
39+
}
40+
41+
children.push(...body);
42+
43+
return {
44+
type: "containerDirective",
45+
name: admonitionKind,
46+
children,
47+
};
48+
}

docs/infra/api-markdown-documenter/api-documentation-layout.mjs

Lines changed: 68 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,75 +6,86 @@
66
//@ts-check
77
/** @typedef {import("@fluid-tools/api-markdown-documenter").ApiItem} ApiItem */
88
/** @typedef {import("@fluid-tools/api-markdown-documenter").ApiItemTransformationConfiguration} ApiItemTransformationConfiguration */
9-
/** @typedef {import("@fluid-tools/api-markdown-documenter").BlockContent} BlockContent */
10-
/** @typedef {import("@fluid-tools/api-markdown-documenter").DocumentationNode} DocumentationNode */
9+
/** @typedef {import("@fluid-tools/api-markdown-documenter").Section} Section */
10+
/** @typedef {import("mdast").BlockContent} BlockContent */
11+
/** @typedef {import("mdast").Paragraph} Paragraph */
1112

1213
import {
1314
ApiItemKind,
1415
ApiItemUtilities,
15-
CodeSpanNode,
16-
HeadingNode,
1716
LayoutUtilities,
18-
LinkNode,
19-
ParagraphNode,
20-
PlainTextNode,
2117
ReleaseTag,
22-
SectionNode,
2318
transformTsdoc,
2419
} from "@fluid-tools/api-markdown-documenter";
2520

26-
import { AdmonitionNode } from "./admonition-node.mjs";
21+
import { createAdmonition } from "./admonition.mjs";
2722

2823
const customExamplesSectionTitle = "Usage";
2924
const customThrowsSectionTitle = "Error Handling";
3025

31-
const supportDocsLinkParagraph = new ParagraphNode([
32-
new PlainTextNode("For more information about our API support guarantees, see "),
33-
new LinkNode(
34-
"here",
35-
// Is there a URL that would be relative to the current site? (For development use)
36-
"https://fluidframework.com/docs/build/releases-and-apitags/#api-support-levels",
37-
),
38-
new PlainTextNode("."),
39-
]);
26+
/**
27+
* A paragraph containing a link to the Fluid Framework API support documentation.
28+
* @type Paragraph
29+
*/
30+
const supportDocsLinkParagraph = {
31+
type: "paragraph",
32+
children: [
33+
{ type: "text", value: "For more information about our API support guarantees, see " },
34+
{
35+
type: "link",
36+
children: [{ type: "text", value: "here" }],
37+
// Is there a URL that would be relative to the current site? (For development use)
38+
url: "https://fluidframework.com/docs/build/releases-and-apitags/#api-support-levels",
39+
},
40+
{ type: "text", value: "." },
41+
],
42+
};
4043

4144
/**
4245
* A special use notice for the "@system" tag.
4346
*/
44-
const systemNotice = new AdmonitionNode(
47+
const systemNotice = createAdmonition(
4548
[supportDocsLinkParagraph],
4649
/* admonitionKind: */ "warning",
47-
"This API is reserved for internal system use and should not be imported directly. It may change at any time without notice.",
50+
/* title: */ "This API is reserved for internal system use and should not be imported directly. It may change at any time without notice.",
4851
);
4952

5053
/**
5154
* A special use notice for the "@sealed" tag.
5255
*/
53-
const sealedNotice = new AdmonitionNode(
56+
const sealedNotice = createAdmonition(
5457
[
55-
new ParagraphNode([
56-
new PlainTextNode(
57-
'This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.',
58-
),
59-
]),
58+
{
59+
type: "paragraph",
60+
children: [
61+
{
62+
type: "text",
63+
value: 'This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.',
64+
},
65+
],
66+
},
6067
],
6168
/* admonitionKind: */ "info",
62-
"Sealed",
69+
/* title: */ "Sealed",
6370
);
6471

6572
/**
6673
* A special use notice for the "@input" tag.
6774
*/
68-
const inputNotice = new AdmonitionNode(
75+
const inputNotice = createAdmonition(
6976
[
70-
new ParagraphNode([
71-
new PlainTextNode(
72-
'This type is "input," meaning that code outside of the library defining it should not read from it. Future versions of this type may add optional members or make typing of members more general.',
73-
),
74-
]),
77+
{
78+
type: "paragraph",
79+
children: [
80+
{
81+
type: "text",
82+
value: 'This type is "input," meaning that code outside of the library defining it should not read from it. Future versions of this type may add optional members or make typing of members more general.',
83+
},
84+
],
85+
},
7586
],
7687
/* admonitionKind: */ "info",
77-
"Input",
88+
/* title: */ "Input",
7889
);
7990

8091
/**
@@ -104,28 +115,29 @@ function createSupportNotice(apiItem, isImportable) {
104115
* @param {string} importSubpath - Subpath beneath the item's package through which the item can be imported.
105116
* @param {string} admonitionTitle - Title to display for the admonition.
106117
*/
107-
function createAdmonition(importSubpath, admonitionTitle) {
118+
function createImportAdmonition(importSubpath, admonitionTitle) {
108119
/** @type {BlockContent[]} */
109120
const admonitionChildren = [];
110121
if (isImportable) {
111-
admonitionChildren.push(
112-
new ParagraphNode([
113-
new PlainTextNode("To use, import via "),
114-
CodeSpanNode.createFromPlainText(`${packageName}/${importSubpath}`),
115-
new PlainTextNode("."),
116-
]),
117-
);
122+
admonitionChildren.push({
123+
type: "paragraph",
124+
children: [
125+
{ type: "text", value: "To use, import via " },
126+
{ type: "inlineCode", value: `${packageName}/${importSubpath}` },
127+
{ type: "text", value: "." },
128+
],
129+
});
118130
}
119131
admonitionChildren.push(supportDocsLinkParagraph);
120-
return new AdmonitionNode(
132+
return createAdmonition(
121133
admonitionChildren,
122134
/* admonitionKind: */ "warning",
123135
admonitionTitle,
124136
);
125137
}
126138

127139
if (ApiItemUtilities.ancestryHasModifierTag(apiItem, "@legacy")) {
128-
return createAdmonition(
140+
return createImportAdmonition(
129141
"legacy",
130142
"This API is provided for existing users, but is not recommended for new users.",
131143
);
@@ -134,14 +146,14 @@ function createSupportNotice(apiItem, isImportable) {
134146
const releaseLevel = ApiItemUtilities.getEffectiveReleaseLevel(apiItem);
135147

136148
if (releaseLevel === ReleaseTag.Alpha) {
137-
return createAdmonition(
149+
return createImportAdmonition(
138150
"alpha",
139151
"This API is provided as an alpha preview and may change without notice.",
140152
);
141153
}
142154

143155
if (releaseLevel === ReleaseTag.Beta) {
144-
return createAdmonition(
156+
return createImportAdmonition(
145157
"beta",
146158
"This API is provided as a beta preview and may change without notice.",
147159
);
@@ -159,7 +171,7 @@ function createSupportNotice(apiItem, isImportable) {
159171
* @param {`@${string}`} tag - The tag to check for.
160172
* @param {boolean} includeContainingAncestry - Whether or not to include the `apiItem`'s containing ancestry when checking for the tag.
161173
* E.g. whether or not a class member should inherit the tag from its containing class. Or a class inherit from its containing package/namespace.
162-
* @param {AdmonitionNode} notice - The notice to display if the tag is present.
174+
* @param {BlockContent} notice - The notice to display if the tag is present.
163175
*/
164176
function createTagNotice(apiItem, tag, includeContainingAncestry, notice) {
165177
if (includeContainingAncestry && ApiItemUtilities.ancestryHasModifierTag(apiItem, tag)) {
@@ -199,7 +211,7 @@ function createTagNotice(apiItem, tag, includeContainingAncestry, notice) {
199211
* 1. See (if any)
200212
*
201213
* @param {ApiItem} apiItem - The API item being rendered.
202-
* @param {SectionNode[] | undefined} itemSpecificContent - API item-specific details to be included in the default layout.
214+
* @param {Section[] | undefined} itemSpecificContent - API item-specific details to be included in the default layout.
203215
* @param {ApiItemTransformationConfiguration} config - Transformation configuration.
204216
*
205217
* @returns An array of sections describing the layout. See {@link @fluid-tools/api-markdown-documenter#ApiItemTransformationConfiguration.createDefaultLayout}.
@@ -224,12 +236,12 @@ export function layoutContent(apiItem, itemSpecificContent, config) {
224236

225237
/**
226238
* Adds node (if not undefined) to `sections`, wrapping in a `SectionNode` if not already a `SectionNode`.
227-
* @param {DocumentationNode | undefined} node - The node to add to `sections`.
239+
* @param {Section | BlockContent | undefined} node - The node to add to `sections`.
228240
* @returns true if the node was added, false otherwise.
229241
*/
230242
function addSection(node) {
231243
if (node !== undefined) {
232-
sections.push(node instanceof SectionNode ? new SectionNode([node]) : node);
244+
sections.push(node.type === "section" ? node : { type: "section", children: [node] });
233245
return true;
234246
}
235247
return false;
@@ -279,12 +291,11 @@ export function layoutContent(apiItem, itemSpecificContent, config) {
279291
return isDocumentItem
280292
? sections
281293
: [
282-
new SectionNode(
283-
sections,
284-
HeadingNode.createFromPlainTextHeading(
285-
ApiItemUtilities.getHeadingForApiItem(apiItem, config),
286-
),
287-
),
294+
{
295+
type: "section",
296+
children: sections,
297+
heading: ApiItemUtilities.getHeadingForApiItem(apiItem, config),
298+
},
288299
];
289300
}
290301

@@ -310,7 +321,7 @@ function createDeprecationNoticeSection(apiItem, config) {
310321
throw new Error("Failed to transform deprecated block.");
311322
}
312323

313-
return new AdmonitionNode(
324+
return createAdmonition(
314325
transformedDeprecatedBlockContents,
315326
"warning",
316327
"This API is deprecated and will be removed in a future release.",

0 commit comments

Comments
 (0)