typedoc-plugin-markdown
Version:
A plugin for TypeDoc that enables TypeScript API documentation to be generated in Markdown.
250 lines (249 loc) • 10.3 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const path = require("path");
const Handlebars = require("handlebars");
const typedoc_1 = require("typedoc");
const plugins_1 = require("typedoc/dist/lib/converter/plugins");
const models_1 = require("typedoc/dist/lib/models");
const events_1 = require("typedoc/dist/lib/output/events");
const theme_1 = require("typedoc/dist/lib/output/theme");
const breadcrumbs_1 = require("./components/breadcrumbs");
const comments_1 = require("./components/comments");
const options_1 = require("./components/options");
const toc_1 = require("./components/toc");
class MarkdownTheme extends theme_1.Theme {
constructor(renderer, basePath) {
super(renderer, basePath);
this.listenTo(renderer, events_1.PageEvent.END, this.onPageEnd, 1024);
renderer.removeComponent('assets');
renderer.removeComponent('javascript-index');
renderer.removeComponent('toc');
renderer.removeComponent('pretty-print');
renderer.removeComponent('marked-links');
renderer.removeComponent('legend');
renderer.removeComponent('navigation');
renderer.addComponent('options', new options_1.ContextAwareHelpers(renderer));
renderer.addComponent('breadcrumbs', new breadcrumbs_1.Breadcrumbs(renderer));
renderer.addComponent('comments', new comments_1.Comments(renderer));
renderer.addComponent('toc', new toc_1.TableOfContents(renderer));
}
static formatContents(contents) {
return (contents
.replace(/[\r\n]{3,}/g, '\n\n')
.replace(/!spaces/g, '')
.replace(/^\s+|\s+$/g, '') + '\n');
}
isOutputDirectory(outputDirectory) {
let isOutputDirectory = true;
const listings = fs.readdirSync(outputDirectory);
listings.forEach((listing) => {
if (!this.allowedDirectoryListings().includes(listing)) {
isOutputDirectory = false;
return;
}
});
return isOutputDirectory;
}
allowedDirectoryListings() {
return [
this.entryDocument,
this.globalsFile,
...this.mappings.map((mapping) => mapping.directory),
'media',
'.DS_Store',
];
}
getUrls(project) {
var _a;
const urls = [];
const noReadmeFile = this.readme == path.join(process.cwd(), 'none');
if (noReadmeFile) {
project.url = this.entryDocument;
urls.push(new typedoc_1.UrlMapping(this.entryDocument, project, 'reflection.hbs'));
}
else {
project.url = this.globalsFile;
urls.push(new typedoc_1.UrlMapping(this.globalsFile, project, 'reflection.hbs'));
urls.push(new typedoc_1.UrlMapping(this.entryDocument, project, 'index.hbs'));
}
(_a = project.children) === null || _a === void 0 ? void 0 : _a.forEach((child) => {
if (child instanceof typedoc_1.DeclarationReflection) {
this.buildUrls(child, urls);
}
});
return urls;
}
buildUrls(reflection, urls) {
const mapping = this.mappings.find((mapping) => reflection.kindOf(mapping.kind));
if (mapping) {
if (!reflection.url || !MarkdownTheme.URL_PREFIX.test(reflection.url)) {
const url = this.toUrl(mapping, reflection);
urls.push(new typedoc_1.UrlMapping(url, reflection, mapping.template));
reflection.url = url;
reflection.hasOwnDocument = true;
}
for (const child of reflection.children || []) {
if (mapping.isLeaf) {
this.applyAnchorUrl(child, reflection);
}
else {
this.buildUrls(child, urls);
}
}
}
else if (reflection.parent) {
this.applyAnchorUrl(reflection, reflection.parent);
}
return urls;
}
toUrl(mapping, reflection) {
return mapping.directory + '/' + this.getUrl(reflection) + '.md';
}
getUrl(reflection, relative) {
let url = reflection.getAlias();
if (reflection.parent &&
reflection.parent !== relative &&
!(reflection.parent instanceof typedoc_1.ProjectReflection)) {
url =
this.getUrl(reflection.parent, relative) + this.filenameSeparator + url;
}
return url;
}
applyAnchorUrl(reflection, container) {
if (!reflection.url || !MarkdownTheme.URL_PREFIX.test(reflection.url)) {
const reflectionId = reflection.name.toLowerCase();
const anchor = this.toAnchorRef(reflectionId);
reflection.url = container.url + '#' + anchor;
reflection.anchor = anchor;
reflection.hasOwnDocument = false;
}
reflection.traverse((child) => {
if (child instanceof typedoc_1.DeclarationReflection) {
this.applyAnchorUrl(child, container);
}
});
}
toAnchorRef(reflectionId) {
return reflectionId;
}
getNavigation(project) {
var _a, _b;
const createNavigationItem = (title, url, isLabel, children = []) => {
const navigationItem = new typedoc_1.NavigationItem(title, url);
navigationItem.isLabel = isLabel;
navigationItem.children = children;
const { reflection, parent, cssClasses, ...filteredNavigationItem } = navigationItem;
return filteredNavigationItem;
};
const navigation = createNavigationItem(project.name, undefined, false);
const hasReadme = this.readme !== path.join(process.cwd(), 'none');
if (hasReadme) {
(_a = navigation.children) === null || _a === void 0 ? void 0 : _a.push(createNavigationItem('Readme', this.entryDocument, false));
}
if (this.entryPoints.length === 1) {
(_b = navigation.children) === null || _b === void 0 ? void 0 : _b.push(createNavigationItem('Exports', hasReadme ? this.globalsFile : this.entryDocument, false));
}
this.mappings.forEach((mapping) => {
var _a;
const kind = mapping.kind[0];
const items = project.getReflectionsByKind(kind);
if (items.length > 0) {
const children = items
.map((item) => createNavigationItem(item.getFullName(), item.url, true))
.sort((a, b) => (a.title > b.title ? 1 : -1));
const group = createNavigationItem(plugins_1.GroupPlugin.getKindPlural(kind), undefined, true, children);
(_a = navigation.children) === null || _a === void 0 ? void 0 : _a.push(group);
}
});
return navigation;
}
onPageEnd(page) {
page.contents = page.contents
? MarkdownTheme.formatContents(page.contents)
: '';
}
get mappings() {
return [
{
kind: [models_1.ReflectionKind.Module],
isLeaf: false,
directory: 'modules',
template: 'reflection.hbs',
},
{
kind: [models_1.ReflectionKind.Namespace],
isLeaf: false,
directory: 'modules',
template: 'reflection.hbs',
},
{
kind: [models_1.ReflectionKind.Enum],
isLeaf: false,
directory: 'enums',
template: 'reflection.hbs',
},
{
kind: [models_1.ReflectionKind.Class],
isLeaf: false,
directory: 'classes',
template: 'reflection.hbs',
},
{
kind: [models_1.ReflectionKind.Interface],
isLeaf: false,
directory: 'interfaces',
template: 'reflection.hbs',
},
...(this.allReflectionsHaveOwnDocument
? [
{
kind: [models_1.ReflectionKind.TypeAlias],
isLeaf: true,
directory: 'types',
template: 'reflection.member.hbs',
},
{
kind: [models_1.ReflectionKind.Variable],
isLeaf: true,
directory: 'variables',
template: 'reflection.member.hbs',
},
{
kind: [models_1.ReflectionKind.Function],
isLeaf: true,
directory: 'functions',
template: 'reflection.member.hbs',
},
]
: []),
];
}
get globalsFile() {
return 'modules.md';
}
}
MarkdownTheme.HANDLEBARS = Handlebars.create();
MarkdownTheme.URL_PREFIX = /^(http|ftp)s?:\/\//;
__decorate([
typedoc_1.BindOption('readme')
], MarkdownTheme.prototype, "readme", void 0);
__decorate([
typedoc_1.BindOption('entryPoints')
], MarkdownTheme.prototype, "entryPoints", void 0);
__decorate([
typedoc_1.BindOption('allReflectionsHaveOwnDocument')
], MarkdownTheme.prototype, "allReflectionsHaveOwnDocument", void 0);
__decorate([
typedoc_1.BindOption('filenameSeparator')
], MarkdownTheme.prototype, "filenameSeparator", void 0);
__decorate([
typedoc_1.BindOption('entryDocument')
], MarkdownTheme.prototype, "entryDocument", void 0);
exports.default = MarkdownTheme;