Skip to content

Commit 43bb866

Browse files
authored
feat(api-markdown-documenter): Add documentation domain to mdast transformation (#24787)
Updates the library with a new transformation layer that converts the `DocumentationNode` representation to [mdast](https://github.com/syntax-tree/mdast), and replaces the library's custom Markdown rendering with [mdast-util-to-markdown](https://github.com/syntax-tree/mdast-util-to-markdown). For an example of how the website build will be updated in response to these changes, see here: #25072.
1 parent 62dc0b0 commit 43bb866

File tree

108 files changed

+2384
-2325
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+2384
-2325
lines changed

tools/api-markdown-documenter/CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
## 0.21.0
44

5+
### Add DocumentationNode -> mdast transformation layer
6+
7+
Adds transformation library for generating [mdast](https://github.com/syntax-tree/mdast) from `DocumentationNode`s.
8+
9+
#### Example
10+
11+
```typescript
12+
const modelDirectoryPath = "<PATH-TO-YOUR-DIRECTORY-CONTAINING-API-REPORTS>";
13+
14+
// Create the API Model from our API reports
15+
const apiModel = await loadModel({
16+
modelDirectoryPath,
17+
});
18+
19+
// Transform the API Model to documents
20+
const documents = transformApiModel({
21+
apiModel,
22+
});
23+
24+
// Convert the documents to Markdown via mdast
25+
const markdownDocuments = documents.map((document) => documentToMarkdown(document, {}));
26+
27+
// Use the resulting Markdown documents with your favorite mdast-compatible library!
28+
```
29+
530
### List parsing
631

732
Markdown-like list syntax is now supported in TSDoc comments.

tools/api-markdown-documenter/README.md

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,12 @@ title: Markdown
176176
graph LR
177177
A[ApiModel]
178178
B[Documentation AST]
179-
C[Markdown AST~]
179+
C[Markdown AST]
180180
D[raw Markdown]
181181
182182
A-->|transformApiModel|B
183-
B-->|documentToMarkdown~|C
184-
C-->|MarkdownRenderer.renderMarkdown~|D
183+
B-->|documentToMarkdown|C
184+
C-->|MarkdownRenderer.renderMarkdown|D
185185
186186
A-.->|MarkdownRenderer.renderApiModel|D
187187
B-.->|MarkdownRenderer.renderDocument|D
@@ -207,10 +207,6 @@ graph LR
207207
B-.->|HtmlRenderer.renderDocument|D
208208
```
209209

210-
**Note:** APIs above marked with an `*` are in preview, and may change without notice.
211-
212-
**Note:** APIs above marked with an `~` are planned, but do not yet exist.
213-
214210
For more details on the interior `Documentation AST` ([Abstract Syntax Tree][]) domain, see [Documentation Domain](#documentation-domain) below.
215211

216212
### API-Extractor
@@ -241,7 +237,7 @@ Then, if you need the new node to be usable in specific contexts (e.g., `Phrasin
241237

242238
##### Example
243239

244-
<!-- AUTO-GENERATED-CONTENT:START (INCLUDE_CODE:path=./examples/ExtendDocumentationDomain.ts&language=typescript&start=13&end=35) -->
240+
<!-- AUTO-GENERATED-CONTENT:START (INCLUDE_CODE:path=./examples/ExtendDocumentationDomain.ts&language=typescript&start=17&end=39) -->
245241

246242
<!-- prettier-ignore-start -->
247243
<!-- NOTE: This section is automatically generated by embedding the referenced file contents. Do not update these generated contents directly. -->
@@ -289,6 +285,38 @@ If you would like to add rendering support for a custom `Documentation Domain` n
289285

290286
If you would like to change any or all of this library's default rendering policies, you may simply override the default policies for the desired `type`s.
291287

288+
### ToMarkdown Transformation
289+
290+
This library includes APIs for transforming `Documentation Domain` trees to Markdown syntax trees using [mdast](https://github.com/syntax-tree/mdast).
291+
292+
<!-- AUTO-GENERATED-CONTENT:START (INCLUDE_CODE:path=./examples/ToMarkdown.ts&language=typescript&start=11&end=-5) -->
293+
294+
<!-- prettier-ignore-start -->
295+
<!-- NOTE: This section is automatically generated by embedding the referenced file contents. Do not update these generated contents directly. -->
296+
297+
```typescript
298+
const modelDirectoryPath = "<PATH-TO-YOUR-DIRECTORY-CONTAINING-API-REPORTS>";
299+
300+
// Create the API Model from our API reports
301+
const apiModel = await loadModel({
302+
modelDirectoryPath,
303+
});
304+
305+
// Transform the API Model to documents
306+
const documents = transformApiModel({
307+
apiModel,
308+
});
309+
310+
// Convert the documents to Markdown via mdast
311+
const markdownDocuments = documents.map((document) => documentToMarkdown(document, {}));
312+
313+
// Use the resulting Markdown documents with your favorite mdast-compatible library!
314+
```
315+
316+
<!-- prettier-ignore-end -->
317+
318+
<!-- AUTO-GENERATED-CONTENT:END -->
319+
292320
### HtmlRenderer
293321

294322
This library includes APIs for HTML rendering.
@@ -367,10 +395,12 @@ Other validation may be added in the future as needed.
367395

368396
- Rather than repeatedly walking up a given `ApiItem`'s hierarchy when evaluating paths, links, etc., we could pass down transformation context object containing a running record of the item's hierarchy as we walk the tree.
369397

370-
## Longer-term work
398+
### Longer-term work
371399

372-
- Add `documentToMarkdown` API that generates `mdast` output.
373-
- Update Markdown rendering APIs to leverage the `mdast` and `hast` domain outputs.
400+
- Replace [Documentation Domain](#documentation-domain) with `mdast`.
401+
- The `mdast` ecosystem already supports conversion from `mdast` to HTML and other formats.
402+
There really isn't a reason for this library to have its own proprietary format.
403+
For the couple of special concepts this library does have (e.g. hierarchical sections with contextual heading levels), we can leverage `mdast`'s extensibility model.
374404

375405
<!-- AUTO-GENERATED-CONTENT:START (README_FOOTER) -->
376406

tools/api-markdown-documenter/api-report/api-markdown-documenter.beta.api.md

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,25 @@ import { ApiProperty } from '@microsoft/api-extractor-model';
2525
import { ApiPropertySignature } from '@microsoft/api-extractor-model';
2626
import { ApiTypeAlias } from '@microsoft/api-extractor-model';
2727
import { ApiVariable } from '@microsoft/api-extractor-model';
28+
import type { BlockContent as BlockContent_2 } from 'mdast';
2829
import type { Data } from 'unist';
2930
import { DocSection } from '@microsoft/tsdoc';
3031
import { Excerpt } from '@microsoft/api-extractor-model';
32+
import type { ListItem } from 'mdast';
3133
import type { Literal } from 'unist';
3234
import { NewlineKind } from '@rushstack/node-core-library';
3335
import type { Node as Node_2 } from 'unist';
3436
import type { Nodes } from 'hast';
37+
import type { Nodes as Nodes_2 } from 'mdast';
38+
import { Options } from 'mdast-util-to-markdown';
3539
import type { Parent } from 'unist';
40+
import type { PhrasingContent as PhrasingContent_2 } from 'mdast';
3641
import { ReleaseTag } from '@microsoft/api-extractor-model';
3742
import type { Root } from 'hast';
43+
import type { Root as Root_2 } from 'mdast';
44+
import type { RootContent } from 'mdast';
45+
import type { TableCell } from 'mdast';
46+
import type { TableRow } from 'mdast';
3847
import { TypeParameter } from '@microsoft/api-extractor-model';
3948

4049
// @public
@@ -173,6 +182,14 @@ export interface BlockContentMap {
173182
table: TableNode;
174183
}
175184

185+
// @public
186+
export function blockContentToMarkdown(node: BlockContent, context: ToMarkdownContext): [BlockContent_2];
187+
188+
// @public
189+
export type BlockContentToMarkdownTransformations = {
190+
readonly [K in keyof BlockContentMap]: ToMarkdownTransformation<BlockContentMap[K], BlockContent_2[]>;
191+
};
192+
176193
// @public @sealed
177194
export class CodeSpanNode extends DocumentationLiteralNodeBase<string> {
178195
constructor(value: string);
@@ -338,6 +355,9 @@ export interface DocumentNodeProps {
338355
// @public
339356
export function documentToHtml(document: DocumentNode, config: ToHtmlConfiguration): Root;
340357

358+
// @public
359+
export function documentToMarkdown(document: DocumentNode, config: ToMarkdownConfiguration): Root_2;
360+
341361
// @public
342362
export interface DocumentWriter {
343363
decreaseIndent(): void;
@@ -360,6 +380,7 @@ export namespace DocumentWriter {
360380
export class FencedCodeBlockNode extends DocumentationLiteralNodeBase<string> {
361381
constructor(value: string, language?: string);
362382
static createFromPlainText(text: string, language?: string): FencedCodeBlockNode;
383+
static readonly Empty: FencedCodeBlockNode;
363384
get isEmpty(): boolean;
364385
readonly language?: string;
365386
readonly type = "fencedCode";
@@ -640,38 +661,19 @@ export interface LoggingConfiguration {
640661
// @public
641662
export type LoggingFunction = (message: string | Error, ...parameters: unknown[]) => void;
642663

643-
// @public
644-
export interface MarkdownRenderConfiguration extends LoggingConfiguration {
645-
readonly customRenderers?: MarkdownRenderers;
646-
readonly startingHeadingLevel?: number;
647-
}
648-
649-
// @public
650-
export interface MarkdownRenderContext extends TextFormatting {
651-
readonly customRenderers?: MarkdownRenderers;
652-
readonly headingLevel: number;
653-
readonly insideCodeBlock?: boolean;
654-
readonly insideTable?: boolean;
655-
}
656-
657664
declare namespace MarkdownRenderer {
658665
export {
659666
RenderApiModelAsMarkdownOptions as RenderApiModelOptions,
660667
renderApiModelAsMarkdown as renderApiModel,
661668
RenderDocumentsAsMarkdownOptions as RenderDocumentsOptions,
662669
renderDocumentsAsMarkdown as renderDocuments,
663670
renderDocument_2 as renderDocument,
664-
renderNode,
665-
renderNodes
671+
RenderDocumentAsMarkdownConfiguration,
672+
renderMarkdown
666673
}
667674
}
668675
export { MarkdownRenderer }
669676

670-
// @public
671-
export interface MarkdownRenderers {
672-
readonly [documentationNodeKind: string]: (node: DocumentationNode, writer: DocumentWriter, context: MarkdownRenderContext) => void;
673-
}
674-
675677
export { NewlineKind }
676678

677679
// @public @sealed
@@ -699,6 +701,14 @@ export interface PhrasingContentMap {
699701
text: PlainTextNode;
700702
}
701703

704+
// @public
705+
export function phrasingContentToMarkdown(node: PhrasingContent, context: ToMarkdownContext): [PhrasingContent_2];
706+
707+
// @public
708+
export type PhrasingContentToMarkdownTransformations = {
709+
readonly [K in keyof PhrasingContentMap]: ToMarkdownTransformation<PhrasingContentMap[K], PhrasingContent_2[]>;
710+
};
711+
702712
// @public @sealed
703713
export class PlainTextNode extends DocumentationLiteralNodeBase<string> {
704714
constructor(text: string);
@@ -716,24 +726,28 @@ export { ReleaseTag }
716726
function renderApiModelAsMarkdown(options: RenderApiModelAsMarkdownOptions): Promise<void>;
717727

718728
// @public
719-
interface RenderApiModelAsMarkdownOptions extends ApiItemTransformationOptions, MarkdownRenderConfiguration, FileSystemConfiguration {
729+
interface RenderApiModelAsMarkdownOptions extends ApiItemTransformationOptions, RenderDocumentAsMarkdownConfiguration, FileSystemConfiguration {
720730
}
721731

722732
// @public
723733
function renderDocument(document: DocumentNode, config: RenderDocumentAsHtmlConfiguration): string;
724734

725735
// @public
726-
function renderDocument_2(document: DocumentNode, config: MarkdownRenderConfiguration): string;
736+
function renderDocument_2(document: DocumentNode, config: RenderDocumentAsMarkdownConfiguration): string;
727737

728738
// @public @sealed
729739
export interface RenderDocumentAsHtmlConfiguration extends ToHtmlConfiguration, RenderHtmlConfiguration {
730740
}
731741

742+
// @public @sealed
743+
export interface RenderDocumentAsMarkdownConfiguration extends ToMarkdownConfiguration, RenderMarkdownConfiguration {
744+
}
745+
732746
// @public
733747
function renderDocumentsAsMarkdown(documents: readonly DocumentNode[], options: RenderDocumentsAsMarkdownOptions): Promise<void>;
734748

735749
// @public
736-
interface RenderDocumentsAsMarkdownOptions extends MarkdownRenderConfiguration, FileSystemConfiguration {
750+
interface RenderDocumentsAsMarkdownOptions extends RenderDocumentAsMarkdownConfiguration, FileSystemConfiguration {
737751
}
738752

739753
// @public
@@ -745,14 +759,19 @@ export interface RenderHtmlConfiguration {
745759
}
746760

747761
// @public
748-
function renderNode(node: DocumentationNode, writer: DocumentWriter, context: MarkdownRenderContext): void;
762+
function renderMarkdown(tree: Nodes_2, config: RenderMarkdownConfiguration): string;
749763

750-
// @public
751-
function renderNodes(children: DocumentationNode[], writer: DocumentWriter, childContext: MarkdownRenderContext): void;
764+
// @public @sealed
765+
export interface RenderMarkdownConfiguration {
766+
readonly mdastToMarkdownOptions?: Partial<Options>;
767+
}
752768

753769
// @public
754770
export type SectionContent = BlockContent | SectionNode;
755771

772+
// @public
773+
export function sectionContentToMarkdown(node: SectionContent, context: ToMarkdownContext): RootContent[];
774+
756775
// @public @sealed
757776
export interface SectionHierarchyConfiguration extends DocumentationHierarchyConfigurationBase {
758777
readonly kind: HierarchyKind.Section;
@@ -870,6 +889,31 @@ export interface ToHtmlTransformations {
870889
readonly [documentationNodeKind: string]: ToHtmlTransformation;
871890
}
872891

892+
// @public
893+
export interface ToMarkdownConfiguration extends LoggingConfiguration {
894+
readonly customTransformations?: Partial<ToMarkdownTransformations>;
895+
readonly startingHeadingLevel?: number;
896+
}
897+
898+
// @public
899+
export interface ToMarkdownContext {
900+
readonly headingLevel: number;
901+
readonly logger: Logger;
902+
readonly transformations: ToMarkdownTransformations;
903+
}
904+
905+
// @public
906+
export type ToMarkdownTransformation<TIn extends DocumentationNode = DocumentationNode, TOut extends Nodes_2[] = [Nodes_2]> = (node: TIn, context: ToMarkdownContext) => TOut;
907+
908+
// @public
909+
export type ToMarkdownTransformations = BlockContentToMarkdownTransformations & PhrasingContentToMarkdownTransformations & {
910+
readonly ["heading"]: ToMarkdownTransformation<HeadingNode, BlockContent_2[]>;
911+
readonly ["listItem"]: ToMarkdownTransformation<ListItemNode, [ListItem]>;
912+
readonly ["section"]: ToMarkdownTransformation<SectionNode, RootContent[]>;
913+
readonly ["tableCell"]: ToMarkdownTransformation<TableCellNode, [TableCell]>;
914+
readonly ["tableRow"]: ToMarkdownTransformation<TableRowNode, [TableRow]>;
915+
};
916+
873917
// @public
874918
export type TransformApiItemWithChildren<TApiItem extends ApiItem> = (apiItem: TApiItem, config: ApiItemTransformationConfiguration, generateChildSection: (apiItem: ApiItem) => SectionNode[]) => SectionNode[];
875919

0 commit comments

Comments
 (0)