Reads API Extractor JSON files and generates API documentation in various output formats
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Extensible plugin architecture for customizing API Documenter's markdown documentation generation. The plugin system enables custom page processing, content modification, and integration with external tools while maintaining compatibility with the core documentation workflow.
Define plugins by exporting a manifest that declares available features.
interface IApiDocumenterPluginManifest {
manifestVersion: 1000;
features: IFeatureDefinition[];
}
interface IFeatureDefinition {
featureName: string;
kind: 'MarkdownDocumenterFeature';
subclass: { new (initialization: PluginFeatureInitialization): MarkdownDocumenterFeature };
}Plugin Package Structure:
// my-documenter-plugin/src/index.ts
import {
MarkdownDocumenterFeature,
IApiDocumenterPluginManifest,
PluginFeatureInitialization
} from "@microsoft/api-documenter";
class CustomMarkdownFeature extends MarkdownDocumenterFeature {
public onInitialized(): void {
console.log('Plugin initialized');
}
}
export const apiDocumenterPluginManifest: IApiDocumenterPluginManifest = {
manifestVersion: 1000,
features: [
{
featureName: 'custom-markdown-processor',
kind: 'MarkdownDocumenterFeature',
subclass: CustomMarkdownFeature
}
]
};Base class for creating markdown documentation plugins with lifecycle hooks.
abstract class MarkdownDocumenterFeature extends PluginFeature {
context!: MarkdownDocumenterFeatureContext;
/**
* Called before each markdown file is written, allowing content customization
* @param eventArgs - Event arguments with page content and metadata
*/
onBeforeWritePage(eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs): void;
/**
* Called after all output files have been written
* @param eventArgs - Event arguments for completion phase
*/
onFinished(eventArgs: IMarkdownDocumenterFeatureOnFinishedArgs): void;
}
interface IMarkdownDocumenterFeatureOnBeforeWritePageArgs {
readonly apiItem: ApiItem;
pageContent: string;
readonly outputFilename: string;
}
interface IMarkdownDocumenterFeatureOnFinishedArgs {}Plugin Development Example:
import {
MarkdownDocumenterFeature,
IMarkdownDocumenterFeatureOnBeforeWritePageArgs
} from "@microsoft/api-documenter";
class CustomStyleFeature extends MarkdownDocumenterFeature {
public onBeforeWritePage(eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs): void {
// Add custom CSS classes to headings
eventArgs.pageContent = eventArgs.pageContent.replace(
/^## (.+)$/gm,
'## $1 {.api-heading}'
);
// Add navigation footer
if (eventArgs.apiItem.kind === 'Class') {
eventArgs.pageContent += '\n\n---\n\n[Back to API Reference](./index.md)';
}
}
public onFinished(): void {
console.log('Documentation generation completed with custom styling');
}
}Context object providing access to the API model and documenter functionality.
class MarkdownDocumenterFeatureContext {
/**
* Provides access to the ApiModel for the documentation being generated
*/
readonly apiModel: ApiModel;
/**
* The full path to the output folder
*/
readonly outputFolder: string;
/**
* Exposes functionality of the documenter
*/
readonly documenter: MarkdownDocumenterAccessor;
constructor(options: MarkdownDocumenterFeatureContext);
}Provides access to documenter functionality for plugins.
class MarkdownDocumenterAccessor {
/**
* For a given ApiItem, return its markdown hyperlink
* @param apiItem - The API item to get a link for
* @returns The hyperlink, or undefined if the ApiItem does not have a hyperlink
*/
getLinkForApiItem(apiItem: ApiItem): string | undefined;
}Usage Example:
class CrossReferenceFeature extends MarkdownDocumenterFeature {
public onBeforeWritePage(eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs): void {
// Add cross-references to related API items
const relatedItems = this.findRelatedItems(eventArgs.apiItem);
if (relatedItems.length > 0) {
let seeAlsoSection = '\n\n## See Also\n\n';
for (const item of relatedItems) {
const link = this.context.documenter.getLinkForApiItem(item);
if (link) {
seeAlsoSection += `- [${item.displayName}](${link})\n`;
}
}
eventArgs.pageContent += seeAlsoSection;
}
}
}Core plugin infrastructure classes.
abstract class PluginFeature {
/**
* Exposes various services that can be used by a plugin
*/
context: PluginFeatureContext;
/**
* @param initialization - Plugin initialization object
*/
constructor(initialization: PluginFeatureInitialization);
/**
* Called after the feature is initialized, but before any processing occurs
*/
onInitialized(): void;
}
class PluginFeatureContext {}
class PluginFeatureInitialization {
constructor();
}Plugins are loaded via configuration in the api-documenter.json file:
{
"configFormatVersion": "1.0",
"plugins": [
{
"packageName": "my-documenter-plugin",
"enabled": true,
"options": {
"customOption": "value"
}
}
]
}doc-plugin-apiDocumenterPluginManifest object@microsoft/api-documenter as peer dependencypackage.json Example:
{
"name": "doc-plugin-custom-styles",
"version": "1.0.0",
"main": "lib/index.js",
"peerDependencies": {
"@microsoft/api-documenter": "^7.26.0"
}
}class ContentTransformFeature extends MarkdownDocumenterFeature {
public onBeforeWritePage(eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs): void {
// Transform code blocks to add syntax highlighting
eventArgs.pageContent = eventArgs.pageContent.replace(
/```typescript/g,
'```typescript {.line-numbers}'
);
// Add custom metadata to frontmatter
if (eventArgs.pageContent.startsWith('# ')) {
const title = eventArgs.pageContent.match(/^# (.+)$/m)?.[1];
eventArgs.pageContent = `---\ntitle: ${title}\napiItem: ${eventArgs.apiItem.kind}\n---\n\n${eventArgs.pageContent}`;
}
}
}class ExternalIntegrationFeature extends MarkdownDocumenterFeature {
public onFinished(): void {
// Generate search index
this.generateSearchIndex();
// Upload to documentation hosting service
this.uploadToHostingService();
}
private generateSearchIndex(): void {
// Implementation for search index generation
}
private uploadToHostingService(): void {
// Implementation for uploading docs
}
}Plugin errors are handled gracefully by the core system: