From 6caa4df79b535b187edd2b312e1bc839ec2f0b63 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 12 Sep 2021 11:42:17 +0200 Subject: [PATCH] api-extractor: switch to subclassing instead of monkey patching Signed-off-by: Patrik Oldsberg --- scripts/api-extractor.ts | 142 +++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/scripts/api-extractor.ts b/scripts/api-extractor.ts index f53c46ddf2..5e8393fc78 100644 --- a/scripts/api-extractor.ts +++ b/scripts/api-extractor.ts @@ -33,7 +33,10 @@ import { } from '@microsoft/api-extractor'; import { DocNode, IDocNodeContainerParameters } from '@microsoft/tsdoc'; import { ApiPackage, ApiModel } from '@microsoft/api-extractor-model'; -import { MarkdownDocumenter } from '@microsoft/api-documenter/lib/documenters/MarkdownDocumenter'; +import { + IMarkdownDocumenterOptions, + MarkdownDocumenter, +} from '@microsoft/api-documenter/lib/documenters/MarkdownDocumenter'; import { CustomMarkdownEmitter } from '@microsoft/api-documenter/lib/markdown/CustomMarkdownEmitter'; import { IMarkdownEmitterContext } from '@microsoft/api-documenter/lib/markdown/MarkdownEmitter'; @@ -341,24 +344,6 @@ async function buildDocs({ newModel.addMember(pkg); } - // This is root of the documentation generation, but it's not directly - // responsible for generating markdown, it just constructs an AST that - // is the consumed by an emitter to actually write the files. - const documenter = new MarkdownDocumenter({ - apiModel: newModel, - documenterConfig: { - outputTarget: 'markdown', - newlineKind: '\n', - // De ba dålig kod - configFilePath: '', - configFile: {}, - } as any, - outputFolder: outputDir, - }); - - // We're accessing a lot of internal things... - const anyDocumenter = documenter as any; - // The doc AST need to be extended with custom nodes if we want to // add any extra content. // This one is for the YAML front matter that we need for the microsite. @@ -388,16 +373,6 @@ async function buildDocs({ } } - // It's a strict model, we gotta register the allowed usage of our new node - anyDocumenter._tsdocConfiguration.docNodeManager.registerDocNodes( - '@backstage/docs', - [{ docNodeKind: DocFrontMatter.kind, constructor: DocFrontMatter }], - ); - anyDocumenter._tsdocConfiguration.docNodeManager.registerAllowableChildren( - 'Paragraph', - [DocFrontMatter.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 { @@ -432,54 +407,79 @@ async function buildDocs({ } } - // The emitter is an internal thing, but it's fine to rewrite - anyDocumenter._markdownEmitter = new CustomCustomMarkdownEmitter(newModel); + class CustomMarkdownDocumenter extends (MarkdownDocumenter as any) { + constructor(options: IMarkdownDocumenterOptions) { + super(options); - // Gotta keep this around so we can call the real implementation - const oldWrite = anyDocumenter._writeBreadcrumb; + // 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], + ); - // We don't really get many chances to modify the generated AST - // so we hook in wherever we can. In this case we add the front matter - // just before writing the breadcrumbs at the top. - anyDocumenter._writeBreadcrumb = function patchedWriteBreadcrumb( - output, - apiItem, - ) { - let title; - let description; - - const name = apiItem.getScopedNameWithinPackage(); - if (name) { - title = name; - description = `API reference for ${apiItem.getScopedNameWithinPackage()}`; - } else if (apiItem.kind === 'Model') { - title = 'Package Index'; - description = 'Index of all Backstage Packages'; - } else { - title = apiItem.name; - description = `API Reference for ${apiItem.name}`; + this._markdownEmitter = new CustomCustomMarkdownEmitter(newModel); } - // Add our front matter - output.appendNodeInParagraph( - new DocFrontMatter({ - configuration: this._tsdocConfiguration, - id: this._getFilenameForApiItem(apiItem).slice(0, -3), - title, - description, - }), - ); + // We don't really get many chances to modify the generated AST + // so we hook in wherever we can. In this case we add the front matter + // just before writing the breadcrumbs at the top. + /** @override */ + _writeBreadcrumb(output, apiItem) { + let title; + let description; - // Now write the actual breadcrumbs - oldWrite.call(this, output, apiItem); + const name = apiItem.getScopedNameWithinPackage(); + if (name) { + title = name; + description = `API reference for ${apiItem.getScopedNameWithinPackage()}`; + } else if (apiItem.kind === 'Model') { + title = 'Package Index'; + description = 'Index of all Backstage Packages'; + } else { + title = apiItem.name; + description = `API Reference for ${apiItem.name}`; + } - // 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 - const oldAppendNode = output.appendNode; - output.appendNode = () => { - output.appendNode = oldAppendNode; - }; - }; + // Add our front matter + output.appendNodeInParagraph( + new DocFrontMatter({ + configuration: this._tsdocConfiguration, + id: this._getFilenameForApiItem(apiItem).slice(0, -3), + title, + description, + }), + ); + + // Now write the actual breadcrumbs + super._writeBreadcrumb(output, apiItem); + + // 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 + const oldAppendNode = output.appendNode; + output.appendNode = () => { + output.appendNode = oldAppendNode; + }; + } + } + + // This is root of the documentation generation, but it's not directly + // responsible for generating markdown, it just constructs an AST that + // is the consumed by an emitter to actually write the files. + const documenter = new CustomMarkdownDocumenter({ + apiModel: newModel, + documenterConfig: { + outputTarget: 'markdown', + newlineKind: '\n', + // De ba dålig kod + configFilePath: '', + configFile: {}, + } as any, + outputFolder: outputDir, + }); // Clean up existing stuff and write ALL the docs! await fs.remove(outputDir);