mirror of
https://github.com/tauri-apps/typedocusaurus.git
synced 2026-02-04 02:31:22 +01:00
feat(generation): Generate + save sidebar from this repo
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
node_modules
|
||||
node_modules
|
||||
src/*.d.ts
|
||||
src/*.js
|
||||
@@ -1,31 +0,0 @@
|
||||
const { readdirSync, statSync } = require("fs");
|
||||
const path = require("path");
|
||||
const { dir } = require("console");
|
||||
|
||||
const generateSidebar = (originPath) => {
|
||||
let out = getTree(originPath)
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
const getTree = (dirPath, items = []) => {
|
||||
files = readdirSync(dirPath);
|
||||
|
||||
files.forEach((file) => {
|
||||
console.log(file);
|
||||
if (statSync(dirPath + "/" + file).isDirectory()) {
|
||||
const out = {
|
||||
label: file.charAt(0).toUpperCase() + file.slice(1),
|
||||
type: "category",
|
||||
items: getTree(dirPath + "/" + file, []),
|
||||
};
|
||||
items.push(out);
|
||||
} else {
|
||||
items.push(path.join(__dirname, dirPath, "/", file));
|
||||
}
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
module.exports = generateSidebar;
|
||||
@@ -1,60 +1,35 @@
|
||||
const core = require("@actions/core");
|
||||
const { transformDocs } = require("../main");
|
||||
const generateSidebar = require("../generateSidebar");
|
||||
const { readFile, writeFile } = require("fs").promises;
|
||||
const { rmdir } = require("fs").promises;
|
||||
const { default: generate } = require("../src/plugin");
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
// Where your docs live, should be the folder containing the crates docs
|
||||
const originPath = core.getInput("originPath"); // e.g. "/path/to/project/src/";
|
||||
|
||||
const sidebarFile = process.env["sidebarFile"];
|
||||
// Where you'll save your MD files
|
||||
const targetPath = core.getInput("targetPath"); // e.g. "/path/to/docusaurus/website/docs/api/js/";
|
||||
const docusaurusPath = core.getInput("docusaurusPath");
|
||||
|
||||
/*
|
||||
Where lives your sidebars config file
|
||||
Doesn't have to be JSON but it's easier to change programmatically,
|
||||
you may create your own saving method
|
||||
*/
|
||||
const sidebarPath = core.getInput("sidebarPath"); // e.g. "/path/to/docusaurus/website/sidebars.json";
|
||||
await rmdir(targetPath, { recursive: true });
|
||||
|
||||
// rustdoc uses relative links for crate types relations
|
||||
const linksRoot = core.getInput("linksRoot"); // e.g. "/docs/api/rust/";
|
||||
|
||||
const entryPoints = core.getInput("entryPoints").split(",");
|
||||
|
||||
// await Promise.all(
|
||||
// entryPoints.map((entryPoint) =>
|
||||
// fs.rmdir(targetPath + entryPoint, { recursive: true })
|
||||
// )
|
||||
// );
|
||||
|
||||
// const sidebarItems = (
|
||||
// await Promise.all(
|
||||
// entryPoints.map(async (entryPoint) => ({
|
||||
// entryPoint,
|
||||
// docs: await transformDocs(
|
||||
// originPath + entryPoint,
|
||||
// originPath,
|
||||
// targetPath
|
||||
// ),
|
||||
// }))
|
||||
// )
|
||||
// ).map((item) => generateSidebar(item.docs, item.entryPoint, originPath));
|
||||
const sidebarItems = generateSidebar(item.docs, item.entryPoint, originPath)
|
||||
|
||||
// Automatically add the sidebar items to Docusaurus sidebar file config
|
||||
const sidebarContent = JSON.parse(await readFile(sidebarPath, "utf-8"));
|
||||
const index = sidebarContent.docs[3].items
|
||||
.map((row, index) => (row.label && row.label === "JavaScript" ? index : 0))
|
||||
.reduce((accumulator, value) => accumulator + value);
|
||||
sidebarContent.docs[3].items[index].items = sidebarItems; // Specify where to put the items
|
||||
|
||||
console.log(sidebarContent);
|
||||
// writeFile(sidebarPath, JSON.stringify(sidebarContent, null, 2));
|
||||
await generate(docusaurusPath, {
|
||||
entryPoints: originPath + "src",
|
||||
out: targetPath,
|
||||
entryDocument: "index.md",
|
||||
hideInPageTOC: true,
|
||||
hideBreadcrumbs: true,
|
||||
watch: false,
|
||||
tsconfig: originPath + "tsconfig.json",
|
||||
sidebar: {
|
||||
sidebarFile,
|
||||
},
|
||||
readme: "none",
|
||||
});
|
||||
|
||||
console.log("Tasks completed!");
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
})();
|
||||
})();
|
||||
|
||||
64
index.js
64
index.js
@@ -1,60 +1,36 @@
|
||||
// const core = require("@actions/core");
|
||||
const { transformDocs } = require("./main");
|
||||
const generateSidebar = require("./generateSidebar");
|
||||
const { readFile, writeFile, rmdir } = require("fs").promises;
|
||||
const { rmdir } = require("fs").promises;
|
||||
const { default: generate } = require("./src/plugin");
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
// Where your docs live, should be the folder containing the crates docs
|
||||
const originPath = process.env["originPath"]; // e.g. "/path/to/project/src/";
|
||||
|
||||
const sidebarFile = process.env["sidebarFile"];
|
||||
// Where you'll save your MD files
|
||||
const targetPath = process.env["targetPath"]; // e.g. "/path/to/docusaurus/website/docs/api/js/";
|
||||
|
||||
/*
|
||||
Where lives your sidebars config file
|
||||
Doesn't have to be JSON but it's easier to change programmatically,
|
||||
you may create your own saving method
|
||||
*/
|
||||
const sidebarPath = process.env["sidebarPath"]; // e.g. "/path/to/docusaurus/website/sidebars.json";
|
||||
const docusaurusPath = process.env["docusaurusPath"];
|
||||
await rmdir(targetPath, { recursive: true });
|
||||
|
||||
// rustdoc uses relative links for crate types relations
|
||||
// const linksRoot = core.getInput("linksRoot"); // e.g. "/docs/api/rust/";
|
||||
|
||||
// await Promise.all(
|
||||
// entryPoints.map((entryPoint) =>
|
||||
// rmdir(targetPath + entryPoint, { recursive: true })
|
||||
// )
|
||||
// );
|
||||
|
||||
// const sidebarItems = (
|
||||
// await Promise.all(
|
||||
// entryPoints.map(async (entryPoint) => ({
|
||||
// entryPoint,
|
||||
// docs: await transformDocs(
|
||||
// originPath + entryPoint,
|
||||
// originPath,
|
||||
// targetPath
|
||||
// ),
|
||||
// }))
|
||||
// )
|
||||
// ).map((item) => generateSidebar(item.docs, item.entryPoint, originPath));
|
||||
|
||||
const sidebarItems = generateSidebar(originPath)
|
||||
|
||||
// Automatically add the sidebar items to Docusaurus sidebar file config
|
||||
const sidebarContent = JSON.parse(await readFile(sidebarPath, "utf-8"));
|
||||
const index = sidebarContent.docs[3].items
|
||||
.map((row, index) => (row.label && row.label === "JavaScript" ? index : 0))
|
||||
.reduce((accumulator, value) => accumulator + value);
|
||||
sidebarContent.docs[3].items[index].items = sidebarItems; // Specify where to put the items
|
||||
|
||||
console.log(sidebarContent.docs[3].items[index].items);
|
||||
// writeFile(sidebarPath, JSON.stringify(sidebarContent, null, 2));
|
||||
await generate(docusaurusPath, {
|
||||
entryPoints: originPath + "src",
|
||||
out: targetPath,
|
||||
entryDocument: "index.md",
|
||||
hideInPageTOC: true,
|
||||
hideBreadcrumbs: true,
|
||||
watch: false,
|
||||
tsconfig: originPath + "tsconfig.json",
|
||||
sidebar: {
|
||||
sidebarFile,
|
||||
},
|
||||
readme: "none",
|
||||
});
|
||||
|
||||
console.log("Tasks completed!");
|
||||
} catch (error) {
|
||||
throw error
|
||||
throw error;
|
||||
// core.setFailed(error.message);
|
||||
}
|
||||
})();
|
||||
})();
|
||||
|
||||
13
main.js
13
main.js
@@ -1,13 +0,0 @@
|
||||
|
||||
|
||||
const transformDocs = async (folderPath, originPath, targetPath) => {
|
||||
|
||||
await transform(contents, crateName);
|
||||
await save(results, originPath, targetPath);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
transformDocs,
|
||||
};
|
||||
@@ -4,7 +4,9 @@
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^14.14.35",
|
||||
"typedoc": "^0.20.30",
|
||||
"typedoc-plugin-markdown": "^3.6.0"
|
||||
"typedoc-plugin-markdown": "^3.6.0",
|
||||
"typescript": "^4.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
126
src/front-matter.ts
Normal file
126
src/front-matter.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import { BindOption } from 'typedoc';
|
||||
import { Component } from 'typedoc/dist/lib/converter/components';
|
||||
import { RendererComponent } from 'typedoc/dist/lib/output/components';
|
||||
import { PageEvent } from 'typedoc/dist/lib/output/events';
|
||||
|
||||
import { FrontMatter, Sidebar } from './types';
|
||||
|
||||
import { reflectionTitle } from 'typedoc-plugin-markdown/dist/resources/helpers/reflection-title';
|
||||
|
||||
export interface FrontMatterVars {
|
||||
[key: string]: string | number | boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends YAML block to a string
|
||||
* @param contents - the string to prepend
|
||||
* @param vars - object of required front matter variables
|
||||
*/
|
||||
export const prependYAML = (contents: string, vars: FrontMatterVars) => {
|
||||
return contents
|
||||
.replace(/^/, toYAML(vars) + '\n\n')
|
||||
.replace(/[\r\n]{3,}/g, '\n\n');
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the page title as rendered in the document h1(# title)
|
||||
* @param page
|
||||
*/
|
||||
export const getPageTitle = (page: PageEvent) => {
|
||||
return reflectionTitle.call(page, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts YAML object to a YAML string
|
||||
* @param vars
|
||||
*/
|
||||
const toYAML = (vars: FrontMatterVars) => {
|
||||
const yaml = `---
|
||||
${Object.entries(vars)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${key}: ${
|
||||
typeof value === 'string' ? `"${escapeString(value)}"` : value
|
||||
}`,
|
||||
)
|
||||
.join('\n')}
|
||||
---`;
|
||||
return yaml;
|
||||
};
|
||||
|
||||
// prettier-ignore
|
||||
const escapeString=(str: string) => str.replace(/([^\\])'/g, '$1\\\'');
|
||||
|
||||
@Component({ name: 'front-matter' })
|
||||
export class FrontMatterComponent extends RendererComponent {
|
||||
@BindOption('out')
|
||||
out!: string;
|
||||
@BindOption('sidebar')
|
||||
sidebar!: Sidebar;
|
||||
@BindOption('globalsTitle')
|
||||
globalsTitle!: string;
|
||||
@BindOption('readmeTitle')
|
||||
readmeTitle!: string;
|
||||
@BindOption('entryDocument')
|
||||
entryDocument!: string;
|
||||
|
||||
globalsFile = 'modules.md';
|
||||
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.listenTo(this.application.renderer, {
|
||||
[PageEvent.END]: this.onPageEnd,
|
||||
});
|
||||
}
|
||||
onPageEnd(page: PageEvent) {
|
||||
if (page.contents) {
|
||||
page.contents = prependYAML(page.contents, this.getYamlItems(page));
|
||||
}
|
||||
}
|
||||
|
||||
getYamlItems(page: PageEvent): any {
|
||||
const pageTitle = this.getTitle(page);
|
||||
const sidebarLabel = this.getSidebarLabel(page);
|
||||
let items: FrontMatter = {
|
||||
title: pageTitle,
|
||||
};
|
||||
if (sidebarLabel && sidebarLabel !== pageTitle) {
|
||||
items = { ...items, sidebar_label: sidebarLabel };
|
||||
}
|
||||
return {
|
||||
...items,
|
||||
custom_edit_url: null,
|
||||
hide_title: true,
|
||||
};
|
||||
}
|
||||
|
||||
getSidebarLabel(page: PageEvent) {
|
||||
if (!this.sidebar) {
|
||||
return null;
|
||||
}
|
||||
if (page.url === this.entryDocument) {
|
||||
return page.url === page.project.url
|
||||
? this.sidebar.indexLabel
|
||||
: this.sidebar.readmeLabel;
|
||||
}
|
||||
|
||||
if (page.url === this.globalsFile) {
|
||||
return this.sidebar.indexLabel;
|
||||
}
|
||||
return this.sidebar.fullNames ? page.model.getFullName() : page.model.name;
|
||||
}
|
||||
|
||||
getId(page: PageEvent) {
|
||||
return path.basename(page.url, path.extname(page.url));
|
||||
}
|
||||
|
||||
getTitle(page: PageEvent) {
|
||||
const readmeTitle = this.readmeTitle || page.project.name;
|
||||
if (page.url === this.entryDocument && page.url !== page.project.url) {
|
||||
return readmeTitle;
|
||||
}
|
||||
return getPageTitle(page);
|
||||
}
|
||||
}
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './plugin';
|
||||
113
src/options.ts
Normal file
113
src/options.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import {
|
||||
Application,
|
||||
MixedDeclarationOption,
|
||||
ParameterType,
|
||||
StringDeclarationOption,
|
||||
TSConfigReader,
|
||||
TypeDocReader,
|
||||
} from 'typedoc';
|
||||
|
||||
import { PluginOptions, SidebarOptions } from './types';
|
||||
|
||||
/**
|
||||
* Default plugin options
|
||||
*/
|
||||
const DEFAULT_PLUGIN_OPTIONS: PluginOptions = {
|
||||
id: 'default',
|
||||
docsRoot: 'docs',
|
||||
out: 'api',
|
||||
entryDocument: 'index.md',
|
||||
hideInPageTOC: true,
|
||||
hideBreadcrumbs: true,
|
||||
sidebar: {
|
||||
fullNames: false,
|
||||
sidebarFile: 'typedoc-sidebar.js',
|
||||
indexLabel: 'Table of contents',
|
||||
readmeLabel: 'Readme',
|
||||
sidebarPath: '',
|
||||
},
|
||||
plugin: ['none'],
|
||||
outputDirectory: '',
|
||||
siteDir: '',
|
||||
watch: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge default with user options
|
||||
* @param opts
|
||||
*/
|
||||
export const getOptions = (
|
||||
siteDir: string,
|
||||
opts: Partial<PluginOptions>,
|
||||
): PluginOptions => {
|
||||
// base options
|
||||
let options = {
|
||||
...DEFAULT_PLUGIN_OPTIONS,
|
||||
...opts,
|
||||
};
|
||||
// sidebar
|
||||
if (opts.sidebar === null) {
|
||||
options = { ...options, sidebar: null };
|
||||
} else {
|
||||
const sidebar = {
|
||||
...DEFAULT_PLUGIN_OPTIONS.sidebar,
|
||||
...opts.sidebar,
|
||||
} as SidebarOptions;
|
||||
options = {
|
||||
...options,
|
||||
sidebar: {
|
||||
...sidebar,
|
||||
sidebarPath: path.resolve(siteDir, sidebar.sidebarFile),
|
||||
},
|
||||
};
|
||||
}
|
||||
// additional
|
||||
options = {
|
||||
...options,
|
||||
siteDir,
|
||||
outputDirectory: path.resolve(siteDir, options.docsRoot, options.out),
|
||||
};
|
||||
return options;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add docusaurus options to converter
|
||||
* @param app
|
||||
*/
|
||||
export const addOptions = (app: Application) => {
|
||||
// configure deault typedoc options
|
||||
app.options.addReader(new TypeDocReader());
|
||||
app.options.addReader(new TSConfigReader());
|
||||
|
||||
// expose plugin options to typedoc so we can access if required
|
||||
app.options.addDeclaration({
|
||||
name: 'id',
|
||||
} as StringDeclarationOption);
|
||||
|
||||
app.options.addDeclaration({
|
||||
name: 'docsRoot',
|
||||
} as StringDeclarationOption);
|
||||
|
||||
app.options.addDeclaration({
|
||||
name: 'siteDir',
|
||||
} as MixedDeclarationOption);
|
||||
|
||||
app.options.addDeclaration({
|
||||
name: 'outputDirectory',
|
||||
} as StringDeclarationOption);
|
||||
|
||||
app.options.addDeclaration({
|
||||
name: 'globalsTitle',
|
||||
} as StringDeclarationOption);
|
||||
|
||||
app.options.addDeclaration({
|
||||
name: 'readmeTitle',
|
||||
} as StringDeclarationOption);
|
||||
|
||||
app.options.addDeclaration({
|
||||
name: 'sidebar',
|
||||
type: ParameterType.Mixed,
|
||||
} as MixedDeclarationOption);
|
||||
};
|
||||
52
src/plugin.ts
Normal file
52
src/plugin.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Application } from 'typedoc';
|
||||
import * as MarkdownPlugin from 'typedoc-plugin-markdown';
|
||||
|
||||
import { FrontMatterComponent } from './front-matter';
|
||||
import { addOptions, getOptions } from './options';
|
||||
import { render } from './render';
|
||||
import { SidebarComponent } from './sidebar';
|
||||
import { PluginOptions } from './types';
|
||||
|
||||
|
||||
export default async function generate(
|
||||
siteDir: string,
|
||||
opts: Partial<PluginOptions>,
|
||||
) {
|
||||
// we need to generate an empty sidebar up-front so it can be resolved from sidebars.js
|
||||
const options = getOptions(siteDir, opts);
|
||||
// if (options.sidebar) {
|
||||
// writeSidebar(options.sidebar, 'module.exports=[];');
|
||||
// }
|
||||
|
||||
// initialize and build app
|
||||
const app = new Application();
|
||||
|
||||
// load the markdown plugin
|
||||
MarkdownPlugin(app);
|
||||
|
||||
// customise render
|
||||
app.renderer.render = render;
|
||||
|
||||
// add plugin options
|
||||
addOptions(app);
|
||||
|
||||
// bootstrap typedoc app
|
||||
app.bootstrap(options);
|
||||
|
||||
// add frontmatter component to typedoc renderer
|
||||
app.renderer.addComponent('fm', new FrontMatterComponent(app.renderer));
|
||||
|
||||
// add sidebar component to typedoc renderer
|
||||
app.renderer.addComponent('sidebar', new SidebarComponent(app.renderer));
|
||||
|
||||
// return the generated reflections
|
||||
const project = app.convert();
|
||||
|
||||
// if project is undefined typedoc has a problem - error logging will be supplied by typedoc.
|
||||
if (!project) {
|
||||
return;
|
||||
}
|
||||
|
||||
// generate or watch app
|
||||
return app.generateDocs(project, options.outputDirectory);
|
||||
}
|
||||
34
src/render.ts
Normal file
34
src/render.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ProjectReflection, UrlMapping } from 'typedoc';
|
||||
import { RendererEvent } from 'typedoc/dist/lib/output/events';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
export async function render(
|
||||
project: ProjectReflection,
|
||||
outputDirectory: string,
|
||||
) {
|
||||
if (!this.prepareTheme() || !this.prepareOutputDirectory(outputDirectory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const output = new RendererEvent(
|
||||
RendererEvent.BEGIN,
|
||||
outputDirectory,
|
||||
project,
|
||||
);
|
||||
|
||||
output.settings = this.application.options.getRawValues();
|
||||
output.urls = this.theme!.getUrls(project);
|
||||
|
||||
this.trigger(output);
|
||||
|
||||
if (!output.isDefaultPrevented) {
|
||||
output.urls?.forEach((mapping: UrlMapping, i) => {
|
||||
this.renderDocument(output.createPageEvent(mapping));
|
||||
ts.sys.write(
|
||||
`\rGenerated ${i + 1} of ${output.urls?.length} TypeDoc docs`,
|
||||
);
|
||||
});
|
||||
ts.sys.write(`\n`);
|
||||
this.trigger(RendererEvent.END, output);
|
||||
}
|
||||
}
|
||||
112
src/sidebar.ts
Normal file
112
src/sidebar.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { BindOption } from 'typedoc';
|
||||
import { Component } from 'typedoc/dist/lib/converter/components';
|
||||
import { RendererComponent } from 'typedoc/dist/lib/output/components';
|
||||
import { RendererEvent } from 'typedoc/dist/lib/output/events';
|
||||
|
||||
import { SidebarItem, SidebarOptions } from './types';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
|
||||
@Component({ name: 'sidebar' })
|
||||
export class SidebarComponent extends RendererComponent {
|
||||
@BindOption('sidebar')
|
||||
sidebar!: SidebarOptions;
|
||||
@BindOption('siteDir')
|
||||
siteDir!: string;
|
||||
@BindOption('out')
|
||||
out!: string;
|
||||
|
||||
initialize() {
|
||||
this.listenTo(this.application.renderer, {
|
||||
[RendererEvent.BEGIN]: this.onRendererBegin,
|
||||
});
|
||||
}
|
||||
|
||||
async onRendererBegin(renderer: RendererEvent) {
|
||||
const navigation = this.application.renderer.theme?.getNavigation(
|
||||
renderer.project,
|
||||
);
|
||||
|
||||
const out = this.out.match(/(?:.*)en\/(.*)/)![1];
|
||||
|
||||
// map the navigation object to a Docuaurus sidebar format
|
||||
const sidebarItems = navigation?.children
|
||||
? navigation.children.map((navigationItem) => {
|
||||
if (navigationItem.isLabel) {
|
||||
const sidebarCategoryItems = navigationItem.children
|
||||
? navigationItem.children.map((navItem) => {
|
||||
const url = this.getUrlKey(out, navItem.url);
|
||||
if (navItem.children && navItem.children.length > 0) {
|
||||
const sidebarCategoryChildren = navItem.children.map(
|
||||
(childGroup) =>
|
||||
this.getSidebarCategory(
|
||||
childGroup.title,
|
||||
childGroup.children
|
||||
? childGroup.children.map((childItem) =>
|
||||
this.getUrlKey(out, childItem.url),
|
||||
)
|
||||
: [],
|
||||
),
|
||||
);
|
||||
return this.getSidebarCategory(navItem.title, [
|
||||
url,
|
||||
...sidebarCategoryChildren,
|
||||
]);
|
||||
}
|
||||
return url;
|
||||
})
|
||||
: [];
|
||||
return this.getSidebarCategory(
|
||||
navigationItem.title,
|
||||
sidebarCategoryItems,
|
||||
);
|
||||
}
|
||||
return this.getUrlKey(out, navigationItem.url);
|
||||
})
|
||||
: [];
|
||||
|
||||
const sidebarPath = this.sidebar.sidebarPath;
|
||||
|
||||
const sidebarContent = JSON.parse(await readFile(sidebarPath!, "utf-8"));
|
||||
const index = sidebarContent.docs[3].items
|
||||
.map((row, index) => (row.label && row.label === "JavaScript" ? index : 0))
|
||||
.reduce((accumulator, value) => accumulator + value);
|
||||
sidebarContent.docs[3].items[index].items = sidebarItems; // Specify where to put the items
|
||||
|
||||
writeFile(sidebarPath, JSON.stringify(sidebarContent, null, 2));
|
||||
this.application.logger.success(
|
||||
`TypeDoc sidebar written to ${sidebarPath}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a sidebar category node
|
||||
*/
|
||||
getSidebarCategory(title: string, items: SidebarItem[]) {
|
||||
return {
|
||||
type: 'category',
|
||||
label: title,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the url key for relevant doc
|
||||
*/
|
||||
getUrlKey(out: string, url: string) {
|
||||
const urlKey = url.replace('.md', '');
|
||||
return out ? out + '/' + urlKey : urlKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write content to sidebar file
|
||||
*/
|
||||
export const writeSidebar = (sidebar: SidebarOptions, content: string) => {
|
||||
if (!fs.existsSync(path.dirname(sidebar.sidebarPath))) {
|
||||
fs.mkdirSync(path.dirname(sidebar.sidebarPath));
|
||||
}
|
||||
fs.writeFileSync(sidebar.sidebarPath, content);
|
||||
};
|
||||
46
src/types.ts
Normal file
46
src/types.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
export interface PluginOptions {
|
||||
id: string;
|
||||
docsRoot: string;
|
||||
out: string;
|
||||
sidebar: SidebarOptions | null;
|
||||
readmeTitle?: string;
|
||||
globalsTitle?: string;
|
||||
plugin: string[];
|
||||
readme?: string;
|
||||
disableOutputCheck?: boolean;
|
||||
entryPoints?: string[];
|
||||
entryDocument: string;
|
||||
hideInPageTOC: boolean;
|
||||
hideBreadcrumbs: boolean;
|
||||
siteDir: string;
|
||||
outputDirectory: string;
|
||||
watch: boolean;
|
||||
}
|
||||
|
||||
export interface FrontMatter {
|
||||
id?: string;
|
||||
title: string;
|
||||
slug?: string;
|
||||
sidebar_label?: string;
|
||||
hide_title?: boolean;
|
||||
}
|
||||
|
||||
export interface SidebarOptions {
|
||||
fullNames?: boolean;
|
||||
sidebarFile: string;
|
||||
sidebarPath: string;
|
||||
indexLabel?: string;
|
||||
readmeLabel?: string;
|
||||
}
|
||||
|
||||
export interface Sidebar {
|
||||
[sidebarId: string]: SidebarItem[];
|
||||
}
|
||||
|
||||
export interface SidebarCategory {
|
||||
type: string;
|
||||
label: string;
|
||||
items: SidebarItem[];
|
||||
}
|
||||
|
||||
export type SidebarItem = SidebarCategory | string;
|
||||
23
src/watch.ts
Normal file
23
src/watch.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Application } from 'typedoc';
|
||||
|
||||
import { PluginOptions } from './types';
|
||||
|
||||
/**
|
||||
* Calls TypeDoc's `convertAndWatch` and force trigger sidebars refresh.
|
||||
*/
|
||||
export const convertAndWatch = (app: Application, options: PluginOptions) => {
|
||||
const sidebarsJsPath = path.resolve(options.siteDir, 'sidebars.js');
|
||||
app.convertAndWatch(async (project) => {
|
||||
if (options.sidebar) {
|
||||
// remove typedoc sidebar from require cache
|
||||
delete require.cache[options.sidebar.sidebarPath];
|
||||
// force trigger a sidebars.js refresh
|
||||
const sidebarJsContent = fs.readFileSync(sidebarsJsPath);
|
||||
fs.writeFileSync(sidebarsJsPath, sidebarJsContent);
|
||||
}
|
||||
await app.generateDocs(project, options.outputDirectory);
|
||||
});
|
||||
};
|
||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es2018", "dom"],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": true,
|
||||
"removeComments": false,
|
||||
"sourceMap": false,
|
||||
"strictNullChecks": true,
|
||||
"target": "es2018"
|
||||
}
|
||||
}
|
||||
10
yarn.lock
10
yarn.lock
@@ -2,6 +2,11 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@^14.14.35":
|
||||
version "14.14.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
|
||||
integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==
|
||||
|
||||
at-least-node@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
||||
@@ -254,6 +259,11 @@ typedoc@^0.20.30:
|
||||
shiki "^0.9.2"
|
||||
typedoc-default-themes "^0.12.8"
|
||||
|
||||
typescript@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
|
||||
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.13.0"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.0.tgz#66ed69f7241f33f13531d3d51d5bcebf00df7f69"
|
||||
|
||||
Reference in New Issue
Block a user