add DocCodeSpanLink to allow links with backticks

Signed-off-by: Juan Pablo Garcia Ripa <juanpablog@spotify.com>
This commit is contained in:
Juan Pablo Garcia Ripa
2022-11-22 23:23:55 +01:00
parent 90d759c9ff
commit db00b1a91d
@@ -39,9 +39,17 @@ import {
DocNode,
IDocNodeContainerParameters,
TSDocTagSyntaxKind,
TSDocConfiguration,
DocPlainText,
DocLinkTag,
} from '@microsoft/tsdoc';
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
import { ApiPackage, ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import {
ApiPackage,
ApiModel,
ApiItem,
ApiItemKind,
} from '@microsoft/api-extractor-model';
import {
IMarkdownDocumenterOptions,
MarkdownDocumenter,
@@ -827,6 +835,16 @@ export async function buildDocs({
}
}
// This class only propose is to have a different kind and be able to render links with backticks
class DocCodeSpanLink extends DocLinkTag {
static kind = 'DocCodeSpanLink';
/** @override */
public get kind(): string {
return DocCodeSpanLink.kind;
}
}
// This is where we actually write the markdown and where we can hook
// in the rendering of our own nodes.
class CustomCustomMarkdownEmitter extends CustomMarkdownEmitter {
@@ -845,7 +863,7 @@ export async function buildDocs({
/** @override */
protected writeNode(
docNode: DocNode,
context: IMarkdownEmitterContext,
context: IMarkdownEmitterContext<ICustomMarkdownEmitterOptions>,
docNodeSiblings: boolean,
): void {
switch (docNode.kind) {
@@ -861,6 +879,26 @@ export async function buildDocs({
context.writer.writeLine();
break;
}
case DocCodeSpanLink.kind: {
const node = docNode as DocLinkTag;
if (node.codeDestination) {
// TODO @sarabadu understand if we need `codeDestination` at all on this custom DocCodeSpanLink
super.writeLinkTagWithCodeDestination(node, context);
} else if (node.urlDestination) {
const linkText =
node.linkText !== undefined ? node.linkText : node.urlDestination;
const encodedLinkText = this.getEscapedText(
linkText.replace(/\s+/g, ' '),
);
context.writer.write('[');
context.writer.write(`\`${encodedLinkText}\``);
context.writer.write(`](${node.urlDestination})`);
} else if (node.linkText) {
this.writePlainText(node.linkText, context);
}
break;
}
default:
super.writeNode(docNode, context, docNodeSiblings);
}
@@ -884,13 +922,22 @@ export async function buildDocs({
super(options);
// It's a strict model, we gotta register the allowed usage of our new node
this._tsdocConfiguration.docNodeManager.registerDocNodes(
'@backstage/docs',
[{ docNodeKind: DocFrontMatter.kind, constructor: DocFrontMatter }],
);
this._tsdocConfiguration.docNodeManager.registerAllowableChildren(
'Paragraph',
[DocFrontMatter.kind],
(
this._tsdocConfiguration as TSDocConfiguration
).docNodeManager.registerDocNodes('@backstage/docs', [
{ docNodeKind: DocFrontMatter.kind, constructor: DocFrontMatter },
]);
(
this._tsdocConfiguration as TSDocConfiguration
).docNodeManager.registerDocNodes('@backstage/docs', [
{ docNodeKind: DocCodeSpanLink.kind, constructor: DocCodeSpanLink },
]);
(
this._tsdocConfiguration as TSDocConfiguration
).docNodeManager.registerAllowableChildren('Paragraph', [
DocFrontMatter.kind,
DocCodeSpanLink.kind,
]);
);
this._markdownEmitter = new CustomCustomMarkdownEmitter(newModel);
@@ -941,8 +988,40 @@ export async function buildDocs({
}),
);
// Now write the actual breadcrumbs
super._writeBreadcrumb(output, apiItem);
const configuration: TSDocConfiguration = this._tsdocConfiguration;
output.appendNodeInParagraph(
new DocLinkTag({
configuration,
tagName: '@link',
linkText: 'Home',
urlDestination: this._getLinkFilenameForApiItem(this._apiModel),
}),
);
for (const hierarchyItem of apiItem.getHierarchy()) {
switch (hierarchyItem.kind) {
case ApiItemKind.Model:
case ApiItemKind.EntryPoint:
// We don't show the model as part of the breadcrumb because it is the root-level container.
// We don't show the entry point because today API Extractor doesn't support multiple entry points;
// this may change in the future.
break;
default:
output.appendNodesInParagraph([
new DocPlainText({
configuration,
text: ' > ',
}),
new DocCodeSpanLink({
configuration,
tagName: '@link',
linkText: hierarchyItem.displayName,
urlDestination: this._getLinkFilenameForApiItem(hierarchyItem),
}),
]);
}
}
// We wanna ignore the header that always gets written after the breadcrumb
// This otherwise becomes more or less a duplicate of the title in the front matter